From 5f0f3cc82020ca0fd5a70ded9597e47956829e73 Mon Sep 17 00:00:00 2001 From: kolaente Date: Thu, 5 Mar 2026 10:35:50 +0100 Subject: [PATCH 001/142] chore(deps): update immutable to 5.1.5 --- frontend/pnpm-lock.yaml | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/frontend/pnpm-lock.yaml b/frontend/pnpm-lock.yaml index a4ef09464..6e20144f3 100644 --- a/frontend/pnpm-lock.yaml +++ b/frontend/pnpm-lock.yaml @@ -4266,8 +4266,8 @@ packages: resolution: {integrity: sha512-Hs59xBNfUIunMFgWAbGX5cq6893IbWg4KnrjbYwX3tx0ztorVgTDA6B2sxf8ejHJ4wz8BqGUMYlnzNBer5NvGg==} engines: {node: '>= 4'} - immutable@5.1.4: - resolution: {integrity: sha512-p6u1bG3YSnINT5RQmx/yRZBpenIl30kVxkTLDyHLIMk0gict704Q9n+thfDI7lTRm9vXdDYutVzXhzcThxTnXA==} + immutable@5.1.5: + resolution: {integrity: sha512-t7xcm2siw+hlUM68I+UEOK+z84RzmN59as9DZ7P1l0994DKUWV7UXBMQZVxaoMSRQ+PBZbHCOoBt7a2wxOMt+A==} import-fresh@3.3.0: resolution: {integrity: sha512-veYYhQa+D1QBKznvhUHxb8faxlrwUnxseDAbAp457E0wLNio2bOSKnjYDhMj+YiAq61xrMGhQk9iXVk5FzgQMw==} @@ -11131,7 +11131,7 @@ snapshots: ignore@7.0.5: {} - immutable@5.1.4: {} + immutable@5.1.5: {} import-fresh@3.3.0: dependencies: @@ -12638,7 +12638,7 @@ snapshots: dependencies: '@bufbuild/protobuf': 2.5.2 colorjs.io: 0.5.2 - immutable: 5.1.4 + immutable: 5.1.5 rxjs: 7.8.2 supports-color: 8.1.1 sync-child-process: 1.0.2 @@ -12666,7 +12666,7 @@ snapshots: sass@1.97.3: dependencies: chokidar: 4.0.3 - immutable: 5.1.4 + immutable: 5.1.5 source-map-js: 1.2.1 optionalDependencies: '@parcel/watcher': 2.5.1 From b5d8576c2aa6198faf043a795e02dd312b38f332 Mon Sep 17 00:00:00 2001 From: kolaente Date: Thu, 5 Mar 2026 10:36:04 +0100 Subject: [PATCH 002/142] chore(deps): update svgo to 3.3.3 --- frontend/pnpm-lock.yaml | 22 +++++++++++----------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/frontend/pnpm-lock.yaml b/frontend/pnpm-lock.yaml index 6e20144f3..426907c1a 100644 --- a/frontend/pnpm-lock.yaml +++ b/frontend/pnpm-lock.yaml @@ -2594,10 +2594,6 @@ packages: '@tootallnate/quickjs-emscripten@0.23.0': resolution: {integrity: sha512-C5Mc6rdnsaJDjO3UpGW/CQTHtCKaYlScZTly4JIu97Jxo/odCiH0ITnDXSJPTOrEKk/ycSZ0AOgTmkDtkOsvIA==} - '@trysound/sax@0.2.0': - resolution: {integrity: sha512-L7z9BgrNEcYyUYtF+HaEfiS5ebkh9jXqbszz7pC0hRBPaatV0XjSD3+eHrpqFemQfgwiFF0QPIarnIihIDn7OA==} - engines: {node: '>=10.13.0'} - '@tsconfig/node24@24.0.4': resolution: {integrity: sha512-2A933l5P5oCbv6qSxHs7ckKwobs8BDAe9SJ/Xr2Hy+nDlwmLE1GhFh/g/vXGRZWgxBg9nX/5piDtHR9Dkw/XuA==} @@ -5743,6 +5739,10 @@ packages: engines: {node: '>=14.0.0'} hasBin: true + sax@1.5.0: + resolution: {integrity: sha512-21IYA3Q5cQf089Z6tgaUTr7lDAyzoTPx5HRtbhsME8Udispad8dC/+sziTNugOEx54ilvatQ9YCzl4KQLPcRHA==} + engines: {node: '>=11.0.0'} + saxes@6.0.0: resolution: {integrity: sha512-xAg7SOnEhrm5zI3puOOKyy1OMcMlIJZYNJY7xLBwSze0UjhPLnWfj2GF2EpT0jmzaJKIWKHLsaSSajf35bcYnA==} engines: {node: '>=v12.22.7'} @@ -6101,8 +6101,8 @@ packages: svg-tags@1.0.0: resolution: {integrity: sha512-ovssysQTa+luh7A5Weu3Rta6FJlFBBbInjOh722LIt6klpU2/HtdUbszju/G4devcvk8PGt7FCLv5wftu3THUA==} - svgo@3.3.2: - resolution: {integrity: sha512-OoohrmuUlBs8B8o6MB2Aevn+pRIH9zDALSR+6hhqVfa6fRwG/Qw9VUMSMW9VNg2CFc/MTIfabtdOVl9ODIJjpw==} + svgo@3.3.3: + resolution: {integrity: sha512-+wn7I4p7YgJhHs38k2TNjy1vCfPIfLIJWR5MnCStsN8WuuTcBnRKcMHQLMM2ijxGZmDoZwNv8ipl5aTTen62ng==} engines: {node: '>=14.0.0'} hasBin: true @@ -9159,8 +9159,6 @@ snapshots: '@tootallnate/quickjs-emscripten@0.23.0': {} - '@trysound/sax@0.2.0': {} - '@tsconfig/node24@24.0.4': {} '@types/chai@5.2.2': @@ -12672,6 +12670,8 @@ snapshots: '@parcel/watcher': 2.5.1 optional: true + sax@1.5.0: {} + saxes@6.0.0: dependencies: xmlchars: 2.2.0 @@ -13084,15 +13084,15 @@ snapshots: svg-tags@1.0.0: {} - svgo@3.3.2: + svgo@3.3.3: dependencies: - '@trysound/sax': 0.2.0 commander: 7.2.0 css-select: 5.1.0 css-tree: 2.3.1 css-what: 6.1.0 csso: 5.0.5 picocolors: 1.1.1 + sax: 1.5.0 symbol-tree@3.2.4: {} @@ -13512,7 +13512,7 @@ snapshots: vite-svg-loader@5.1.0(vue@3.5.27(typescript@5.9.3)): dependencies: - svgo: 3.3.2 + svgo: 3.3.3 vue: 3.5.27(typescript@5.9.3) vite@7.3.1(@types/node@24.11.0)(jiti@2.4.2)(lightningcss@1.31.1)(sass-embedded@1.97.3)(sass@1.97.3)(terser@5.31.6)(yaml@2.5.0): From f5595f0ed2bb46dce9c1496c3b057c39e1098dd1 Mon Sep 17 00:00:00 2001 From: kolaente Date: Thu, 5 Mar 2026 10:38:31 +0100 Subject: [PATCH 003/142] chore(deps): update tar to 7.5.10 and @tootallnate/once to 3.0.1 in desktop Both are major version overrides for transitive dependencies of electron-builder to address security advisories. --- desktop/package.json | 4 +- desktop/pnpm-lock.yaml | 84 +++++++++++------------------------------- 2 files changed, 24 insertions(+), 64 deletions(-) diff --git a/desktop/package.json b/desktop/package.json index 6437d9dc4..3e2b4248b 100644 --- a/desktop/package.json +++ b/desktop/package.json @@ -64,7 +64,9 @@ "electron" ], "overrides": { - "minimatch": "^10.2.3" + "minimatch": "^10.2.3", + "tar": "^7.5.10", + "@tootallnate/once": "^3.0.1" } } } diff --git a/desktop/pnpm-lock.yaml b/desktop/pnpm-lock.yaml index 8c6a410b5..19c58845d 100644 --- a/desktop/pnpm-lock.yaml +++ b/desktop/pnpm-lock.yaml @@ -6,6 +6,8 @@ settings: overrides: minimatch: ^10.2.3 + tar: ^7.5.10 + '@tootallnate/once': ^3.0.1 importers: @@ -122,8 +124,8 @@ packages: resolution: {integrity: sha512-4BAffykYOgO+5nzBWYwE3W90sBgLJoUPRWWcL8wlyiM8IB8ipJz3UMJ9KXQd1RKQXpKp8Tutn80HZtWsu2u76w==} engines: {node: '>=10'} - '@tootallnate/once@2.0.0': - resolution: {integrity: sha512-XCuKFP5PS55gnMVu3dty8KPatLqUoy/ZYzDzAGCQ8JNFCkLXzmI7vNHCR+XpbZaMWQK/vQubr7PkYq8g470J/A==} + '@tootallnate/once@3.0.1': + resolution: {integrity: sha512-VyMVKRrpHTT8PnotUeV8L/mDaMwD5DaAKCFLP73zAqAtvF0FCqky+Ki7BYbFCYQmqFyTe9316Ed5zS70QUR9eg==} engines: {node: '>= 10'} '@types/cacheable-request@6.0.3': @@ -343,10 +345,6 @@ packages: resolution: {integrity: sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==} engines: {node: '>=10'} - chownr@2.0.0: - resolution: {integrity: sha512-bIomtDF5KGpdogkLd9VspvFzk9KfpyyGlS8YFVZl7TGPBHL5snIOnxeshwVgPteQ9b4Eydl+pVbIyE1DcvCWgQ==} - engines: {node: '>=10'} - chownr@3.0.0: resolution: {integrity: sha512-+IxzY9BZOQd/XuYPRmrvEVjF/nqj5kgT4kEq7VofrDoM1MxoRjEWkrCC3EtLi59TVawxTAn+orJwFQcrqEN1+g==} engines: {node: '>=18'} @@ -696,10 +694,6 @@ packages: resolution: {integrity: sha512-hcg3ZmepS30/7BSFqRvoo3DOMQu7IjqxO5nCDt+zM9XWjb33Wg7ziNT+Qvqbuc3+gWpzO02JubVyk2G4Zvo1OQ==} engines: {node: '>=10'} - fs-minipass@2.1.0: - resolution: {integrity: sha512-V/JgOLFCS+R6Vcq0slCuaeWEdNC3ouDlJMNIsacH2VtALiu9mV4LPrHc5cDl8k5aw6J8jwgWWpiTo5RYhmIzvg==} - engines: {node: '>= 8'} - fs-minipass@3.0.3: resolution: {integrity: sha512-XUBA9XClHbnJWSfBzjkm6RvPsyg3sryZt06BEQoXcF7EK/xpGaQYJgQKDJSUH5SGZ76Y7pFx1QBnXz09rU5Fbw==} engines: {node: ^14.17.0 || ^16.13.0 || >=18.0.0} @@ -1042,27 +1036,14 @@ packages: resolution: {integrity: sha512-DxiNidxSEK+tHG6zOIklvNOwm3hvCrbUrdtzY74U6HKTJxvIDfOUL5W5P2Ghd3DTkhhKPYGqeNUIh5qcM4YBfw==} engines: {node: '>=8'} - minipass@5.0.0: - resolution: {integrity: sha512-3FnjYuehv9k6ovOEbyOswadCDPX1piCfhV8ncmYtHOjuPwylVWsghTLo7rabjC3Rx5xD4HDx8Wm1xnMF7S5qFQ==} - engines: {node: '>=8'} - minipass@7.1.2: resolution: {integrity: sha512-qOOzS1cBTWYF4BH8fVePDBOO9iptMnGUEZwNc/cMWnTV2nVLZ7VoNWEPHkYczZA0pdoA7dl6e7FL659nX9S2aw==} engines: {node: '>=16 || 14 >=14.17'} - minizlib@2.1.2: - resolution: {integrity: sha512-bAxsR8BVfj60DWXHE3u30oHzfl4G7khkSuPW+qvpd7jFRHm7dLxOjUk1EHACJ/hxLY8phGJ0YhYHZo7jil7Qdg==} - engines: {node: '>= 8'} - minizlib@3.1.0: resolution: {integrity: sha512-KZxYo1BUkWD2TVFLr0MQoM8vUUigWD3LlD83a/75BqC+4qE0Hb1Vo5v1FgcfaNXvfXzr+5EhQ6ing/CaBijTlw==} engines: {node: '>= 18'} - mkdirp@1.0.4: - resolution: {integrity: sha512-vVqVZQyf3WLx2Shd0qJ9xuvqgAyKPLAiqITEtqW0oIUjzo3PePDd6fW9iFz30ef7Ysp/oiWqbhszeGWW2T6Gzw==} - engines: {node: '>=10'} - hasBin: true - ms@2.1.3: resolution: {integrity: sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==} @@ -1282,6 +1263,10 @@ packages: resolution: {integrity: sha512-1n3r/tGXO6b6VXMdFT54SHzT9ytu9yr7TaELowdYpMqY/Ao7EnlQGmAQ1+RatX7Tkkdm6hONI2owqNx2aZj5Sw==} engines: {node: '>=11.0.0'} + sax@1.5.0: + resolution: {integrity: sha512-21IYA3Q5cQf089Z6tgaUTr7lDAyzoTPx5HRtbhsME8Udispad8dC/+sziTNugOEx54ilvatQ9YCzl4KQLPcRHA==} + engines: {node: '>=11.0.0'} + semver-compare@1.0.0: resolution: {integrity: sha512-YM3/ITh2MJ5MtzaM429anh+x2jiLVjqILF4m4oyQB18W7Ggea7BfqdH/wGMK7dDiMghv/6WG7znWMwUDzJiXow==} @@ -1420,13 +1405,8 @@ packages: resolution: {integrity: sha512-ujeqbceABgwMZxEJnk2HDY2DlnUZ+9oEcb1KzTVfYHio0UE6dG71n60d8D2I4qNvleWrrXpmjpt7vZeF1LnMZQ==} engines: {node: '>=6'} - tar@6.2.1: - resolution: {integrity: sha512-DZ4yORTwrbTj/7MZYq2w+/ZFdI6OZ/f9SFHR+71gIVUZhOQPHzVCLpvRnPgyaMpfWxxk/4ONva3GQSyNIKRv6A==} - engines: {node: '>=10'} - deprecated: Old versions of tar are not supported, and contain widely publicized security vulnerabilities, which have been fixed in the current version. Please update. Support for old versions may be purchased (at exorbitant rates) by contacting i@izs.me - - tar@7.5.9: - resolution: {integrity: sha512-BTLcK0xsDh2+PUe9F6c2TlRp4zOOBMTkoQHQIWSIzI0R7KG46uEwq4OPk2W7bZcprBMsuaeFsqwYr7pjh6CuHg==} + tar@7.5.10: + resolution: {integrity: sha512-8mOPs1//5q/rlkNSPcCegA6hiHJYDmSLEI8aMH/CdSQJNWztHC9WHNam5zdQlfpTwB9Xp7IBEsHfV5LKMJGVAw==} engines: {node: '>=18'} temp-file@3.4.0: @@ -1667,7 +1647,7 @@ snapshots: ora: 5.4.1 read-binary-file-arch: 1.0.6 semver: 7.7.4 - tar: 7.5.9 + tar: 7.5.10 yargs: 17.7.2 transitivePeerDependencies: - supports-color @@ -1749,7 +1729,7 @@ snapshots: dependencies: defer-to-connect: 2.0.1 - '@tootallnate/once@2.0.0': {} + '@tootallnate/once@3.0.1': {} '@types/cacheable-request@6.0.3': dependencies: @@ -1867,7 +1847,7 @@ snapshots: read-config-file: 6.3.2 sanitize-filename: 1.6.3 semver: 7.7.4 - tar: 6.2.1 + tar: 7.5.10 temp-file: 3.4.0 transitivePeerDependencies: - supports-color @@ -1908,7 +1888,7 @@ snapshots: proper-lockfile: 4.1.2 resedit: 1.7.2 semver: 7.7.4 - tar: 7.5.9 + tar: 7.5.10 temp-file: 3.4.0 tiny-async-pool: 1.3.0 which: 5.0.0 @@ -2018,7 +1998,7 @@ snapshots: builder-util-runtime@9.2.4: dependencies: debug: 4.4.3 - sax: 1.4.4 + sax: 1.5.0 transitivePeerDependencies: - supports-color @@ -2085,7 +2065,7 @@ snapshots: minipass-pipeline: 1.2.4 p-map: 7.0.4 ssri: 12.0.0 - tar: 7.5.9 + tar: 7.5.10 unique-filename: 4.0.0 cacheable-lookup@5.0.4: {} @@ -2115,8 +2095,6 @@ snapshots: ansi-styles: 4.3.0 supports-color: 7.2.0 - chownr@2.0.0: {} - chownr@3.0.0: {} chromium-pickle-js@0.2.0: {} @@ -2536,10 +2514,6 @@ snapshots: jsonfile: 6.2.0 universalify: 2.0.1 - fs-minipass@2.1.0: - dependencies: - minipass: 3.3.6 - fs-minipass@3.0.3: dependencies: minipass: 7.1.2 @@ -2657,7 +2631,7 @@ snapshots: http-proxy-agent@5.0.0: dependencies: - '@tootallnate/once': 2.0.0 + '@tootallnate/once': 3.0.1 agent-base: 6.0.2 debug: 4.4.3 transitivePeerDependencies: @@ -2900,21 +2874,12 @@ snapshots: dependencies: yallist: 4.0.0 - minipass@5.0.0: {} - minipass@7.1.2: {} - minizlib@2.1.2: - dependencies: - minipass: 3.3.6 - yallist: 4.0.0 - minizlib@3.1.0: dependencies: minipass: 7.1.2 - mkdirp@1.0.4: {} - ms@2.1.3: {} negotiator@1.0.0: {} @@ -2939,7 +2904,7 @@ snapshots: nopt: 8.1.0 proc-log: 5.0.0 semver: 7.7.4 - tar: 7.5.9 + tar: 7.5.10 tinyglobby: 0.2.15 which: 5.0.0 transitivePeerDependencies: @@ -3149,6 +3114,8 @@ snapshots: sax@1.4.4: {} + sax@1.5.0: {} + semver-compare@1.0.0: optional: true @@ -3318,16 +3285,7 @@ snapshots: inherits: 2.0.4 readable-stream: 3.6.2 - tar@6.2.1: - dependencies: - chownr: 2.0.0 - fs-minipass: 2.1.0 - minipass: 5.0.0 - minizlib: 2.1.2 - mkdirp: 1.0.4 - yallist: 4.0.0 - - tar@7.5.9: + tar@7.5.10: dependencies: '@isaacs/fs-minipass': 4.0.1 chownr: 3.0.0 From 1b1e8e5b19e9dd32a0d6089759d18c81883f8ffc Mon Sep 17 00:00:00 2001 From: kolaente Date: Thu, 5 Mar 2026 12:28:58 +0100 Subject: [PATCH 004/142] feat: add InitEventsForTesting and Unfake for real event dispatch in tests InitEventsForTesting sets up a real Watermill GoChannel router with a cancellable context, returning a readiness channel. Skips Prometheus metrics and poison queue to avoid duplicate registration panics. Unfake re-enables real event dispatch after test init helpers call Fake(). Also guards Dispatch against nil pubsub with a clear error message. --- pkg/events/events.go | 64 +++++++++++++++++++++++++++++++++++++++++++ pkg/events/testing.go | 8 ++++++ 2 files changed, 72 insertions(+) diff --git a/pkg/events/events.go b/pkg/events/events.go index 57b02dc37..30c26ea99 100644 --- a/pkg/events/events.go +++ b/pkg/events/events.go @@ -139,6 +139,66 @@ func InitEvents() (err error) { return router.Run(context.Background()) } +// InitEventsForTesting sets up the event system like InitEvents but accepts a +// context so the watermill router can be shut down cleanly in tests. +// It starts the router in a background goroutine and returns a channel that is +// closed once the router is ready to accept messages. +func InitEventsForTesting(ctx context.Context) (<-chan struct{}, error) { + logger := log.NewWatermillLogger(config.LogEnabled.GetBool(), config.LogEvents.GetString(), config.LogEventsLevel.GetString(), config.LogFormat.GetString()) + + router, err := message.NewRouter( + message.RouterConfig{}, + logger, + ) + if err != nil { + return nil, err + } + + pubsub = gochannel.NewGoChannel( + gochannel.Config{ + OutputChannelBuffer: 1024, + }, + logger, + ) + + // No prometheus metrics in tests — avoids duplicate registration panics + // No poison queue — keep test output clean, let errors surface directly + + handlerTracker := func(h message.HandlerFunc) message.HandlerFunc { + return func(msg *message.Message) ([]*message.Message, error) { + activeHandlers.Add(1) + defer activeHandlers.Done() + return h(msg) + } + } + + router.AddMiddleware( + handlerTracker, + middleware.Retry{ + MaxRetries: 3, + InitialInterval: time.Millisecond * 50, + MaxInterval: time.Second, + Multiplier: 2, + Logger: logger, + }.Middleware, + middleware.Recoverer, + ) + + for topic, funcs := range listeners { + for _, handler := range funcs { + router.AddConsumerHandler(topic+"."+handler.Name(), topic, pubsub, handler.Handle) + } + } + + ready := router.Running() + go func() { + if err := router.Run(ctx); err != nil { + log.Errorf("Event system error: %s", err) + } + }() + return ready, nil +} + // Dispatch dispatches an event func Dispatch(event Event) error { if isUnderTest { @@ -146,6 +206,10 @@ func Dispatch(event Event) error { return nil } + if pubsub == nil { + return fmt.Errorf("event system not initialized: call InitEvents or InitEventsForTesting before dispatching") + } + content, err := json.Marshal(event) if err != nil { return err diff --git a/pkg/events/testing.go b/pkg/events/testing.go index b422e7c20..2c969f057 100644 --- a/pkg/events/testing.go +++ b/pkg/events/testing.go @@ -39,6 +39,14 @@ func Fake() { dispatchedTestEvents = nil } +// Unfake disables "test mode" so that events are dispatched through the real +// watermill pub/sub instead of being recorded. Call this after Fake() when you +// need the full event pipeline (e.g. in end-to-end tests). +func Unfake() { + isUnderTest = false + dispatchedTestEvents = nil +} + // AssertDispatched asserts an event has been dispatched. func AssertDispatched(t *testing.T, event Event) { var found bool From 1f3509bf27a9102ac96578d441d3731fb444dfa9 Mon Sep 17 00:00:00 2001 From: kolaente Date: Thu, 5 Mar 2026 12:29:04 +0100 Subject: [PATCH 005/142] test: add e2e API test package with webhook pipeline verification New pkg/e2etests/ package runs with the real Watermill event system to verify the full async pipeline: web handler -> DB -> event dispatch -> Watermill -> listener -> side effect. First test (TestTaskUpdateWebhookE2E) updates a task and asserts that a webhook HTTP POST arrives at a test server. --- pkg/e2etests/integrations.go | 146 +++++++++++++++++++++++++++++++++++ pkg/e2etests/main_test.go | 32 ++++++++ pkg/e2etests/webhook_test.go | 97 +++++++++++++++++++++++ 3 files changed, 275 insertions(+) create mode 100644 pkg/e2etests/integrations.go create mode 100644 pkg/e2etests/main_test.go create mode 100644 pkg/e2etests/webhook_test.go diff --git a/pkg/e2etests/integrations.go b/pkg/e2etests/integrations.go new file mode 100644 index 000000000..4a0b18bd6 --- /dev/null +++ b/pkg/e2etests/integrations.go @@ -0,0 +1,146 @@ +// Vikunja is a to-do list application to facilitate your life. +// Copyright 2018-present Vikunja and contributors. All rights reserved. +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU Affero General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU Affero General Public License for more details. +// +// You should have received a copy of the GNU Affero General Public License +// along with this program. If not, see . + +package e2etests + +import ( + "context" + "net/http" + "net/http/httptest" + "net/url" + "strings" + "sync" + "testing" + + "code.vikunja.io/api/pkg/config" + "code.vikunja.io/api/pkg/db" + "code.vikunja.io/api/pkg/events" + "code.vikunja.io/api/pkg/files" + "code.vikunja.io/api/pkg/log" + "code.vikunja.io/api/pkg/models" + "code.vikunja.io/api/pkg/modules/auth" + "code.vikunja.io/api/pkg/modules/keyvalue" + "code.vikunja.io/api/pkg/routes" + "code.vikunja.io/api/pkg/user" + "code.vikunja.io/api/pkg/web/handler" + + "github.com/golang-jwt/jwt/v5" + "github.com/labstack/echo/v5" + "github.com/stretchr/testify/require" +) + +var registerListenersOnce sync.Once + +// Test users matching the fixture data in pkg/db/fixtures/users.yml +var ( + testuser1 = user.User{ + ID: 1, + Username: "user1", + Password: "$2a$14$dcadBoMBL9jQoOcZK8Fju.cy0Ptx2oZECkKLnaa8ekRoTFe1w7To.", + Email: "user1@example.com", + Issuer: "local", + } +) + +// setupE2ETestEnv initializes the full application environment with real events. +// Unlike setupTestEnv in pkg/webtests/, this does NOT call events.Fake(), +// so events are dispatched through the real Watermill router to registered listeners. +func setupE2ETestEnv(ctx context.Context) (e *echo.Echo, err error) { + config.InitDefaultConfig() + config.ServicePublicURL.Set("https://localhost") + config.WebhooksEnabled.Set(true) + + log.InitLogger() + + files.InitTests() + user.InitTests() + models.SetupTests() //nolint:contextcheck + keyvalue.InitStorage() + + err = db.LoadFixtures() + if err != nil { + return + } + + // Register all listeners (including webhook listener) before starting the router. + // This must happen before InitEventsForTesting because the router wires up + // all listeners that were registered via events.RegisterListener(). + // Use sync.Once because RegisterListeners appends to the global registry + // and calling it multiple times would stack duplicate handlers. + registerListenersOnce.Do(models.RegisterListeners) + + // Start the real watermill event system. InitEventsForTesting initializes + // pubsub and starts the router in a background goroutine, returning a + // channel that closes once the router is ready. + ready, err := events.InitEventsForTesting(ctx) + if err != nil { + return + } + + // user.InitTests() calls events.Fake() which sets isUnderTest=true and + // prevents real event dispatch. Undo that now that pubsub is initialized. + events.Unfake() + + // Wait for the router to be ready before proceeding. + <-ready + + e = routes.NewEcho() //nolint:contextcheck + routes.RegisterRoutes(e) //nolint:contextcheck + return +} + +// createRequest builds an httptest request and echo context, mirroring webtests.createRequest +func createRequest(e *echo.Echo, method string, payload string, queryParam url.Values, urlParams map[string]string) (c *echo.Context, rec *httptest.ResponseRecorder) { + req := httptest.NewRequest(method, "/", strings.NewReader(payload)) + req.Header.Set(echo.HeaderContentType, echo.MIMEApplicationJSON) + req.URL.RawQuery = queryParam.Encode() + rec = httptest.NewRecorder() + + c = e.NewContext(req, rec) + if len(urlParams) > 0 { + pathValues := make(echo.PathValues, 0, len(urlParams)) + for name, value := range urlParams { + pathValues = append(pathValues, echo.PathValue{Name: name, Value: value}) + } + c.SetPathValues(pathValues) + } + return +} + +// addUserTokenToContext creates a JWT for the user and sets it on the echo context +func addUserTokenToContext(t *testing.T, u *user.User, c *echo.Context) { + token, err := auth.NewUserJWTAuthtoken(u, "test-session-id") + require.NoError(t, err) + tken, err := jwt.Parse(token, func(_ *jwt.Token) (interface{}, error) { + return []byte(config.ServiceJWTSecret.GetString()), nil + }) + require.NoError(t, err) + c.Set("user", tken) +} + +// testUpdateWithUser performs a POST (update) request as the given user +func testUpdateWithUser(e *echo.Echo, t *testing.T, u *user.User, urlParams map[string]string, payload string) (rec *httptest.ResponseRecorder, err error) { + c, rec := createRequest(e, http.MethodPost, payload, nil, urlParams) + addUserTokenToContext(t, u, c) + + hndl := handler.WebHandler{ + EmptyStruct: func() handler.CObject { + return &models.Task{} + }, + } + err = hndl.UpdateWeb(c) + return +} diff --git a/pkg/e2etests/main_test.go b/pkg/e2etests/main_test.go new file mode 100644 index 000000000..83641694a --- /dev/null +++ b/pkg/e2etests/main_test.go @@ -0,0 +1,32 @@ +// Vikunja is a to-do list application to facilitate your life. +// Copyright 2018-present Vikunja and contributors. All rights reserved. +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU Affero General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU Affero General Public License for more details. +// +// You should have received a copy of the GNU Affero General Public License +// along with this program. If not, see . + +package e2etests + +import ( + "flag" + "os" + "testing" +) + +func TestMain(m *testing.M) { + flag.Parse() + if testing.Short() { + println("-short requested, skipping e2e tests") + return + } + os.Exit(m.Run()) +} diff --git a/pkg/e2etests/webhook_test.go b/pkg/e2etests/webhook_test.go new file mode 100644 index 000000000..0fe4755a7 --- /dev/null +++ b/pkg/e2etests/webhook_test.go @@ -0,0 +1,97 @@ +// Vikunja is a to-do list application to facilitate your life. +// Copyright 2018-present Vikunja and contributors. All rights reserved. +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU Affero General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU Affero General Public License for more details. +// +// You should have received a copy of the GNU Affero General Public License +// along with this program. If not, see . + +package e2etests + +import ( + "context" + "encoding/json" + "io" + "net/http" + "net/http/httptest" + "testing" + "time" + + "code.vikunja.io/api/pkg/db" + "code.vikunja.io/api/pkg/models" + + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" +) + +func TestTaskUpdateWebhookE2E(t *testing.T) { + ctx, cancel := context.WithCancel(context.Background()) + defer cancel() + + e, err := setupE2ETestEnv(ctx) + require.NoError(t, err) + + // Start a test HTTP server to capture webhook payloads. + // Use a non-blocking send so retries or duplicate deliveries don't hang. + webhookReceived := make(chan []byte, 1) + ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + body, _ := io.ReadAll(r.Body) + select { + case webhookReceived <- body: + default: + } + w.WriteHeader(http.StatusOK) + })) + defer ts.Close() + + // Clean up any leftover webhook rows from previous test runs, then insert + // a fresh webhook for project 1 listening to "task.updated". + s := db.NewSession() + defer s.Close() + _, err = s.Where("1=1").Delete(&models.Webhook{}) + require.NoError(t, err) + _, err = s.Insert(&models.Webhook{ + TargetURL: ts.URL, + Events: []string{"task.updated"}, + ProjectID: 1, + CreatedByID: 1, + }) + require.NoError(t, err) + require.NoError(t, s.Commit()) + + // Update task 1 via the web handler — this triggers the full pipeline: + // UpdateWeb → Task.Update() → DispatchOnCommit → s.Commit() → + // DispatchPending → Dispatch → watermill → WebhookListener.Handle → + // HTTP POST to ts.URL + rec, err := testUpdateWithUser(e, t, &testuser1, + map[string]string{"projecttask": "1"}, + `{"title":"E2E webhook test"}`, + ) + require.NoError(t, err) + assert.Contains(t, rec.Body.String(), `"title":"E2E webhook test"`) + + // Wait for the webhook payload to arrive via the real async pipeline + select { + case body := <-webhookReceived: + var payload map[string]interface{} + require.NoError(t, json.Unmarshal(body, &payload)) + assert.Equal(t, "task.updated", payload["event_name"]) + + data, ok := payload["data"].(map[string]interface{}) + require.True(t, ok, "payload.data should be a map") + task, ok := data["task"].(map[string]interface{}) + require.True(t, ok, "payload.data.task should be a map") + assert.Equal(t, "E2E webhook test", task["title"]) + + case <-time.After(10 * time.Second): + t.Fatal("Webhook payload not received within 10s timeout") + } +} From 24b800d48d27a90447bfb9765f23093e5b9bde41 Mon Sep 17 00:00:00 2001 From: kolaente Date: Thu, 5 Mar 2026 12:29:08 +0100 Subject: [PATCH 006/142] feat: add mage test:e2e-api target for e2e API tests --- magefile.go | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/magefile.go b/magefile.go index e7782c89c..ba5634527 100644 --- a/magefile.go +++ b/magefile.go @@ -73,6 +73,7 @@ var ( "dev:prepare-worktree": Dev.PrepareWorktree, "dev:tag-release": Dev.TagRelease, "test:e2e": Test.E2E, + "test:e2e-api": Test.E2EApi, "plugins:build": Plugins.Build, "lint": Check.Golangci, "lint:fix": Check.GolangciFix, @@ -424,7 +425,15 @@ func (Test) Filter(filter string) error { func (Test) All() { mg.Deps(initVars) - mg.Deps(Test.Feature, Test.Web) + mg.Deps(Test.Feature, Test.Web, Test.E2EApi) +} + +// E2EApi runs the end-to-end API tests in pkg/e2etests. +// These tests use the real event system (not events.Fake()) to verify +// the full async pipeline: web handler → DB → event dispatch → watermill → listener. +func (Test) E2EApi() error { + mg.Deps(initVars) + return runAndStreamOutput("go", "test", goDetectVerboseFlag(), "-p", "1", "-timeout", "45m", "./pkg/e2etests") } // E2E builds the API, starts it with an in-memory database and the frontend dev server, From 62eb72c9f7c35aa28d21c5998de36d7ae2e69e40 Mon Sep 17 00:00:00 2001 From: kolaente Date: Thu, 5 Mar 2026 12:29:11 +0100 Subject: [PATCH 007/142] ci: add e2e API tests to CI pipeline --- .github/workflows/test.yml | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 5e1106387..ec82fb162 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -178,6 +178,16 @@ jobs: test: - feature - web + - e2e-api + exclude: + - db: sqlite + test: e2e-api + - db: postgres + test: e2e-api + - db: mysql + test: e2e-api + - db: paradedb + test: e2e-api services: db-mysql: image: ${{ matrix.db == 'mysql' && 'mariadb:12@sha256:5b6a1eac15b85b981a61afb89aea2a22bf76b5f58809d05f0bcc13ab6ec44cb8' || '' }} From d7722d01930598d92b555f47b5389c2d89d22257 Mon Sep 17 00:00:00 2001 From: Noah Neukam <38350116+n-nkm@users.noreply.github.com> Date: Thu, 5 Mar 2026 12:50:04 +0100 Subject: [PATCH 008/142] fix(menu): prevent dropdown from closing when cursor crosses offset gap (#2367) --- frontend/src/components/misc/Dropdown.vue | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/frontend/src/components/misc/Dropdown.vue b/frontend/src/components/misc/Dropdown.vue index 579eaba69..f87227b89 100644 --- a/frontend/src/components/misc/Dropdown.vue +++ b/frontend/src/components/misc/Dropdown.vue @@ -68,9 +68,11 @@ defineSlots<{ const initialMount = ref(false) const open = ref(false) + const dropdown = ref() const dropdownMenu = ref() const dropdownPosition = ref({x: 0, y: 0}) +const dropdownMenuOffset = computed(() => 4) function close() { open.value = false @@ -87,7 +89,7 @@ async function updatePosition() { placement: 'bottom-end', strategy: 'absolute', middleware: [ - offset(4), + offset(dropdownMenuOffset.value), autoPlacement({ allowedPlacements: ['bottom-end', 'top-end', 'bottom-start', 'top-start'], padding: 8, @@ -102,6 +104,7 @@ async function updatePosition() { const dropdownMenuStyle = computed(() => ({ left: `${dropdownPosition.value.x}px`, top: `${dropdownPosition.value.y}px`, + '--hover-offset': `${dropdownMenuOffset.value}px`, })) function toggleOpen() { @@ -129,6 +132,12 @@ onClickOutside(dropdown, (e) => { position: relative; } +.dropdown-menu::before { + content: ""; + position: absolute; + inset: calc(var(--hover-offset) * -1); +} + .dropdown-menu { min-inline-size: 12rem; position: absolute; From 275f714224cc93f0f9cd7b4590ba2b07a79398e4 Mon Sep 17 00:00:00 2001 From: kolaente Date: Thu, 5 Mar 2026 00:02:59 +0100 Subject: [PATCH 009/142] test: add fixture task with compound word for prefix search testing --- pkg/db/fixtures/tasks.yml | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/pkg/db/fixtures/tasks.yml b/pkg/db/fixtures/tasks.yml index b17b5b76a..e8298d7ed 100644 --- a/pkg/db/fixtures/tasks.yml +++ b/pkg/db/fixtures/tasks.yml @@ -420,3 +420,12 @@ index: 32 created: 2018-12-01 01:12:04 updated: 2018-12-01 01:12:04 +- id: 48 + title: 'Landingpages update' + description: 'Update all landingpages with new branding' + done: false + created_by_id: 1 + project_id: 1 + index: 33 + created: 2018-12-01 01:12:04 + updated: 2018-12-01 01:12:04 From 892b38b3b696e024e673dba3c0e302d5afa714fe Mon Sep 17 00:00:00 2001 From: kolaente Date: Thu, 5 Mar 2026 00:06:10 +0100 Subject: [PATCH 010/142] test: add web tests for prefix/substring search (#2346) --- pkg/webtests/task_collection_test.go | 30 ++++++++++++++++++++++++---- 1 file changed, 26 insertions(+), 4 deletions(-) diff --git a/pkg/webtests/task_collection_test.go b/pkg/webtests/task_collection_test.go index ce3ac2f02..62b6023cd 100644 --- a/pkg/webtests/task_collection_test.go +++ b/pkg/webtests/task_collection_test.go @@ -109,13 +109,30 @@ func TestTaskCollection(t *testing.T) { assert.NotContains(t, rec.Body.String(), `task #13`) assert.NotContains(t, rec.Body.String(), `task #14`) }) + t.Run("Search prefix match", func(t *testing.T) { + // Issue #2346: searching "landing" should match "Landingpages update" + rec, err := testHandler.testReadAllWithUser(url.Values{"s": []string{"landing"}}, urlParams) + require.NoError(t, err) + assert.Contains(t, rec.Body.String(), `Landingpages update`) + assert.NotContains(t, rec.Body.String(), `task #1`) + }) + t.Run("Search prefix match case insensitive", func(t *testing.T) { + rec, err := testHandler.testReadAllWithUser(url.Values{"s": []string{"LANDING"}}, urlParams) + require.NoError(t, err) + assert.Contains(t, rec.Body.String(), `Landingpages update`) + }) + t.Run("Search prefix match in description", func(t *testing.T) { + rec, err := testHandler.testReadAllWithUser(url.Values{"s": []string{"branding"}}, urlParams) + require.NoError(t, err) + assert.Contains(t, rec.Body.String(), `Landingpages update`) + }) t.Run("Sort Order", func(t *testing.T) { // TODO: Add more cases // should equal priority asc t.Run("by priority", func(t *testing.T) { rec, err := testHandler.testReadAllWithUser(url.Values{"sort_by": []string{"priority"}}, urlParams) require.NoError(t, err) - assert.Contains(t, rec.Body.String(), `{"id":33,"title":"task #33 with percent done","description":"","done":false,"done_at":"0001-01-01T00:00:00Z","due_date":"0001-01-01T00:00:00Z","reminders":null,"project_id":1,"repeat_after":0,"repeat_mode":0,"priority":0,"start_date":"0001-01-01T00:00:00Z","end_date":"0001-01-01T00:00:00Z","assignees":null,"labels":null,"hex_color":"","percent_done":0.5,"identifier":"test1-17","index":17,"related_tasks":{},"attachments":null,"cover_image_attachment_id":0,"is_favorite":false,"created":"2018-12-01T01:12:04Z","updated":"2018-12-01T01:12:04Z","bucket_id":0,"position":0,"reactions":null,"created_by":{"id":1,"name":"","username":"user1","created":"2018-12-01T15:13:12Z","updated":"2018-12-02T15:13:12Z"}},{"id":47,"title":"task #47 with reminders outside window","description":"","done":false,"done_at":"0001-01-01T00:00:00Z","due_date":"0001-01-01T00:00:00Z","reminders":[{"reminder":"2018-08-01T12:00:00Z","relative_period":0,"relative_to":""},{"reminder":"2019-03-01T12:00:00Z","relative_period":0,"relative_to":""}],"project_id":1,"repeat_after":0,"repeat_mode":0,"priority":0,"start_date":"0001-01-01T00:00:00Z","end_date":"0001-01-01T00:00:00Z","assignees":null,"labels":null,"hex_color":"","percent_done":0,"identifier":"test1-32","index":32,"related_tasks":{},"attachments":null,"cover_image_attachment_id":0,"is_favorite":false,"created":"2018-12-01T01:12:04Z","updated":"2018-12-01T01:12:04Z","bucket_id":0,"position":0,"reactions":null,"created_by":{"id":1,"name":"","username":"user1","created":"2018-12-01T15:13:12Z","updated":"2018-12-02T15:13:12Z"}}]`) + assert.Contains(t, rec.Body.String(), `{"id":33,"title":"task #33 with percent done","description":"","done":false,"done_at":"0001-01-01T00:00:00Z","due_date":"0001-01-01T00:00:00Z","reminders":null,"project_id":1,"repeat_after":0,"repeat_mode":0,"priority":0,"start_date":"0001-01-01T00:00:00Z","end_date":"0001-01-01T00:00:00Z","assignees":null,"labels":null,"hex_color":"","percent_done":0.5,"identifier":"test1-17","index":17,"related_tasks":{},"attachments":null,"cover_image_attachment_id":0,"is_favorite":false,"created":"2018-12-01T01:12:04Z","updated":"2018-12-01T01:12:04Z","bucket_id":0,"position":0,"reactions":null,"created_by":{"id":1,"name":"","username":"user1","created":"2018-12-01T15:13:12Z","updated":"2018-12-02T15:13:12Z"}},{"id":47,"title":"task #47 with reminders outside window","description":"","done":false,"done_at":"0001-01-01T00:00:00Z","due_date":"0001-01-01T00:00:00Z","reminders":[{"reminder":"2018-08-01T12:00:00Z","relative_period":0,"relative_to":""},{"reminder":"2019-03-01T12:00:00Z","relative_period":0,"relative_to":""}],"project_id":1,"repeat_after":0,"repeat_mode":0,"priority":0,"start_date":"0001-01-01T00:00:00Z","end_date":"0001-01-01T00:00:00Z","assignees":null,"labels":null,"hex_color":"","percent_done":0,"identifier":"test1-32","index":32,"related_tasks":{},"attachments":null,"cover_image_attachment_id":0,"is_favorite":false,"created":"2018-12-01T01:12:04Z","updated":"2018-12-01T01:12:04Z","bucket_id":0,"position":0,"reactions":null,"created_by":{"id":1,"name":"","username":"user1","created":"2018-12-01T15:13:12Z","updated":"2018-12-02T15:13:12Z"}},{"id":48,"title":"Landingpages update","description":"Update all landingpages with new branding","done":false,"done_at":"0001-01-01T00:00:00Z","due_date":"0001-01-01T00:00:00Z","reminders":null,"project_id":1,"repeat_after":0,"repeat_mode":0,"priority":0,"start_date":"0001-01-01T00:00:00Z","end_date":"0001-01-01T00:00:00Z","assignees":null,"labels":null,"hex_color":"","percent_done":0,"identifier":"test1-33","index":33,"related_tasks":{},"attachments":null,"cover_image_attachment_id":0,"is_favorite":false,"created":"2018-12-01T01:12:04Z","updated":"2018-12-01T01:12:04Z","bucket_id":0,"position":0,"reactions":null,"created_by":{"id":1,"name":"","username":"user1","created":"2018-12-01T15:13:12Z","updated":"2018-12-02T15:13:12Z"}}]`) }) t.Run("by priority desc", func(t *testing.T) { rec, err := testHandler.testReadAllWithUser(url.Values{"sort_by": []string{"priority"}, "order_by": []string{"desc"}}, urlParams) @@ -125,7 +142,7 @@ func TestTaskCollection(t *testing.T) { t.Run("by priority asc", func(t *testing.T) { rec, err := testHandler.testReadAllWithUser(url.Values{"sort_by": []string{"priority"}, "order_by": []string{"asc"}}, urlParams) require.NoError(t, err) - assert.Contains(t, rec.Body.String(), `{"id":33,"title":"task #33 with percent done","description":"","done":false,"done_at":"0001-01-01T00:00:00Z","due_date":"0001-01-01T00:00:00Z","reminders":null,"project_id":1,"repeat_after":0,"repeat_mode":0,"priority":0,"start_date":"0001-01-01T00:00:00Z","end_date":"0001-01-01T00:00:00Z","assignees":null,"labels":null,"hex_color":"","percent_done":0.5,"identifier":"test1-17","index":17,"related_tasks":{},"attachments":null,"cover_image_attachment_id":0,"is_favorite":false,"created":"2018-12-01T01:12:04Z","updated":"2018-12-01T01:12:04Z","bucket_id":0,"position":0,"reactions":null,"created_by":{"id":1,"name":"","username":"user1","created":"2018-12-01T15:13:12Z","updated":"2018-12-02T15:13:12Z"}},{"id":47,"title":"task #47 with reminders outside window","description":"","done":false,"done_at":"0001-01-01T00:00:00Z","due_date":"0001-01-01T00:00:00Z","reminders":[{"reminder":"2018-08-01T12:00:00Z","relative_period":0,"relative_to":""},{"reminder":"2019-03-01T12:00:00Z","relative_period":0,"relative_to":""}],"project_id":1,"repeat_after":0,"repeat_mode":0,"priority":0,"start_date":"0001-01-01T00:00:00Z","end_date":"0001-01-01T00:00:00Z","assignees":null,"labels":null,"hex_color":"","percent_done":0,"identifier":"test1-32","index":32,"related_tasks":{},"attachments":null,"cover_image_attachment_id":0,"is_favorite":false,"created":"2018-12-01T01:12:04Z","updated":"2018-12-01T01:12:04Z","bucket_id":0,"position":0,"reactions":null,"created_by":{"id":1,"name":"","username":"user1","created":"2018-12-01T15:13:12Z","updated":"2018-12-02T15:13:12Z"}}]`) + assert.Contains(t, rec.Body.String(), `{"id":33,"title":"task #33 with percent done","description":"","done":false,"done_at":"0001-01-01T00:00:00Z","due_date":"0001-01-01T00:00:00Z","reminders":null,"project_id":1,"repeat_after":0,"repeat_mode":0,"priority":0,"start_date":"0001-01-01T00:00:00Z","end_date":"0001-01-01T00:00:00Z","assignees":null,"labels":null,"hex_color":"","percent_done":0.5,"identifier":"test1-17","index":17,"related_tasks":{},"attachments":null,"cover_image_attachment_id":0,"is_favorite":false,"created":"2018-12-01T01:12:04Z","updated":"2018-12-01T01:12:04Z","bucket_id":0,"position":0,"reactions":null,"created_by":{"id":1,"name":"","username":"user1","created":"2018-12-01T15:13:12Z","updated":"2018-12-02T15:13:12Z"}},{"id":47,"title":"task #47 with reminders outside window","description":"","done":false,"done_at":"0001-01-01T00:00:00Z","due_date":"0001-01-01T00:00:00Z","reminders":[{"reminder":"2018-08-01T12:00:00Z","relative_period":0,"relative_to":""},{"reminder":"2019-03-01T12:00:00Z","relative_period":0,"relative_to":""}],"project_id":1,"repeat_after":0,"repeat_mode":0,"priority":0,"start_date":"0001-01-01T00:00:00Z","end_date":"0001-01-01T00:00:00Z","assignees":null,"labels":null,"hex_color":"","percent_done":0,"identifier":"test1-32","index":32,"related_tasks":{},"attachments":null,"cover_image_attachment_id":0,"is_favorite":false,"created":"2018-12-01T01:12:04Z","updated":"2018-12-01T01:12:04Z","bucket_id":0,"position":0,"reactions":null,"created_by":{"id":1,"name":"","username":"user1","created":"2018-12-01T15:13:12Z","updated":"2018-12-02T15:13:12Z"}},{"id":48,"title":"Landingpages update","description":"Update all landingpages with new branding","done":false,"done_at":"0001-01-01T00:00:00Z","due_date":"0001-01-01T00:00:00Z","reminders":null,"project_id":1,"repeat_after":0,"repeat_mode":0,"priority":0,"start_date":"0001-01-01T00:00:00Z","end_date":"0001-01-01T00:00:00Z","assignees":null,"labels":null,"hex_color":"","percent_done":0,"identifier":"test1-33","index":33,"related_tasks":{},"attachments":null,"cover_image_attachment_id":0,"is_favorite":false,"created":"2018-12-01T01:12:04Z","updated":"2018-12-01T01:12:04Z","bucket_id":0,"position":0,"reactions":null,"created_by":{"id":1,"name":"","username":"user1","created":"2018-12-01T15:13:12Z","updated":"2018-12-02T15:13:12Z"}}]`) }) // should equal duedate asc t.Run("by due_date", func(t *testing.T) { @@ -353,12 +370,17 @@ func TestTaskCollection(t *testing.T) { assert.NotContains(t, rec.Body.String(), `task #13`) assert.NotContains(t, rec.Body.String(), `task #14`) }) + t.Run("Search prefix match", func(t *testing.T) { + rec, err := testHandler.testReadAllWithUser(url.Values{"s": []string{"landing"}}, nil) + require.NoError(t, err) + assert.Contains(t, rec.Body.String(), `Landingpages update`) + }) t.Run("Sort Order", func(t *testing.T) { // should equal priority asc t.Run("by priority", func(t *testing.T) { rec, err := testHandler.testReadAllWithUser(url.Values{"sort_by": []string{"priority"}}, nil) require.NoError(t, err) - assert.Contains(t, rec.Body.String(), `{"id":33,"title":"task #33 with percent done","description":"","done":false,"done_at":"0001-01-01T00:00:00Z","due_date":"0001-01-01T00:00:00Z","reminders":null,"project_id":1,"repeat_after":0,"repeat_mode":0,"priority":0,"start_date":"0001-01-01T00:00:00Z","end_date":"0001-01-01T00:00:00Z","assignees":null,"labels":null,"hex_color":"","percent_done":0.5,"identifier":"test1-17","index":17,"related_tasks":{},"attachments":null,"cover_image_attachment_id":0,"is_favorite":false,"created":"2018-12-01T01:12:04Z","updated":"2018-12-01T01:12:04Z","bucket_id":0,"position":0,"reactions":null,"created_by":{"id":1,"name":"","username":"user1","created":"2018-12-01T15:13:12Z","updated":"2018-12-02T15:13:12Z"}},{"id":35,"title":"task #35","description":"","done":false,"done_at":"0001-01-01T00:00:00Z","due_date":"0001-01-01T00:00:00Z","reminders":null,"project_id":21,"repeat_after":0,"repeat_mode":0,"priority":0,"start_date":"0001-01-01T00:00:00Z","end_date":"0001-01-01T00:00:00Z","assignees":[{"id":2,"name":"","username":"user2","created":"2018-12-01T15:13:12Z","updated":"2018-12-02T15:13:12Z"}],"labels":[{"id":4,"title":"Label #4 - visible via other task","description":"","hex_color":"","created_by":{"id":2,"name":"","username":"user2","created":"2018-12-01T15:13:12Z","updated":"2018-12-02T15:13:12Z"},"created":"2018-12-01T15:13:12Z","updated":"2018-12-02T15:13:12Z"},{"id":5,"title":"Label #5","description":"","hex_color":"","created_by":{"id":2,"name":"","username":"user2","created":"2018-12-01T15:13:12Z","updated":"2018-12-02T15:13:12Z"},"created":"2018-12-01T15:13:12Z","updated":"2018-12-02T15:13:12Z"}],"hex_color":"","percent_done":0,"identifier":"test21-1","index":1,"related_tasks":{"related":[{"id":1,"title":"task #1","description":"Lorem Ipsum","done":false,"done_at":"0001-01-01T00:00:00Z","due_date":"0001-01-01T00:00:00Z","reminders":null,"project_id":1,"repeat_after":0,"repeat_mode":0,"priority":0,"start_date":"0001-01-01T00:00:00Z","end_date":"0001-01-01T00:00:00Z","assignees":null,"labels":null,"hex_color":"","percent_done":0,"identifier":"","index":1,"related_tasks":null,"attachments":null,"cover_image_attachment_id":0,"is_favorite":true,"created":"2018-12-01T01:12:04Z","updated":"2018-12-01T01:12:04Z","bucket_id":0,"position":0,"reactions":null,"created_by":null},{"id":1,"title":"task #1","description":"Lorem Ipsum","done":false,"done_at":"0001-01-01T00:00:00Z","due_date":"0001-01-01T00:00:00Z","reminders":null,"project_id":1,"repeat_after":0,"repeat_mode":0,"priority":0,"start_date":"0001-01-01T00:00:00Z","end_date":"0001-01-01T00:00:00Z","assignees":null,"labels":null,"hex_color":"","percent_done":0,"identifier":"","index":1,"related_tasks":null,"attachments":null,"cover_image_attachment_id":0,"is_favorite":true,"created":"2018-12-01T01:12:04Z","updated":"2018-12-01T01:12:04Z","bucket_id":0,"position":0,"reactions":null,"created_by":null}]},"attachments":null,"cover_image_attachment_id":0,"is_favorite":false,"created":"2018-12-01T01:12:04Z","updated":"2018-12-01T01:12:04Z","bucket_id":0,"position":0,"reactions":null,"created_by":{"id":1,"name":"","username":"user1","created":"2018-12-01T15:13:12Z","updated":"2018-12-02T15:13:12Z"}},{"id":39,"title":"task #39","description":"","done":false,"done_at":"0001-01-01T00:00:00Z","due_date":"0001-01-01T00:00:00Z","reminders":null,"project_id":25,"repeat_after":0,"repeat_mode":0,"priority":0,"start_date":"0001-01-01T00:00:00Z","end_date":"0001-01-01T00:00:00Z","assignees":null,"labels":null,"hex_color":"","percent_done":0,"identifier":"#0","index":0,"related_tasks":{},"attachments":null,"cover_image_attachment_id":0,"is_favorite":false,"created":"2018-12-01T01:12:04Z","updated":"2018-12-01T01:12:04Z","bucket_id":0,"position":0,"reactions":null,"created_by":{"id":1,"name":"","username":"user1","created":"2018-12-01T15:13:12Z","updated":"2018-12-02T15:13:12Z"}},{"id":47,"title":"task #47 with reminders outside window","description":"","done":false,"done_at":"0001-01-01T00:00:00Z","due_date":"0001-01-01T00:00:00Z","reminders":[{"reminder":"2018-08-01T12:00:00Z","relative_period":0,"relative_to":""},{"reminder":"2019-03-01T12:00:00Z","relative_period":0,"relative_to":""}],"project_id":1,"repeat_after":0,"repeat_mode":0,"priority":0,"start_date":"0001-01-01T00:00:00Z","end_date":"0001-01-01T00:00:00Z","assignees":null,"labels":null,"hex_color":"","percent_done":0,"identifier":"test1-32","index":32,"related_tasks":{},"attachments":null,"cover_image_attachment_id":0,"is_favorite":false,"created":"2018-12-01T01:12:04Z","updated":"2018-12-01T01:12:04Z","bucket_id":0,"position":0,"reactions":null,"created_by":{"id":1,"name":"","username":"user1","created":"2018-12-01T15:13:12Z","updated":"2018-12-02T15:13:12Z"}}]`) + assert.Contains(t, rec.Body.String(), `{"id":33,"title":"task #33 with percent done","description":"","done":false,"done_at":"0001-01-01T00:00:00Z","due_date":"0001-01-01T00:00:00Z","reminders":null,"project_id":1,"repeat_after":0,"repeat_mode":0,"priority":0,"start_date":"0001-01-01T00:00:00Z","end_date":"0001-01-01T00:00:00Z","assignees":null,"labels":null,"hex_color":"","percent_done":0.5,"identifier":"test1-17","index":17,"related_tasks":{},"attachments":null,"cover_image_attachment_id":0,"is_favorite":false,"created":"2018-12-01T01:12:04Z","updated":"2018-12-01T01:12:04Z","bucket_id":0,"position":0,"reactions":null,"created_by":{"id":1,"name":"","username":"user1","created":"2018-12-01T15:13:12Z","updated":"2018-12-02T15:13:12Z"}},{"id":35,"title":"task #35","description":"","done":false,"done_at":"0001-01-01T00:00:00Z","due_date":"0001-01-01T00:00:00Z","reminders":null,"project_id":21,"repeat_after":0,"repeat_mode":0,"priority":0,"start_date":"0001-01-01T00:00:00Z","end_date":"0001-01-01T00:00:00Z","assignees":[{"id":2,"name":"","username":"user2","created":"2018-12-01T15:13:12Z","updated":"2018-12-02T15:13:12Z"}],"labels":[{"id":4,"title":"Label #4 - visible via other task","description":"","hex_color":"","created_by":{"id":2,"name":"","username":"user2","created":"2018-12-01T15:13:12Z","updated":"2018-12-02T15:13:12Z"},"created":"2018-12-01T15:13:12Z","updated":"2018-12-02T15:13:12Z"},{"id":5,"title":"Label #5","description":"","hex_color":"","created_by":{"id":2,"name":"","username":"user2","created":"2018-12-01T15:13:12Z","updated":"2018-12-02T15:13:12Z"},"created":"2018-12-01T15:13:12Z","updated":"2018-12-02T15:13:12Z"}],"hex_color":"","percent_done":0,"identifier":"test21-1","index":1,"related_tasks":{"related":[{"id":1,"title":"task #1","description":"Lorem Ipsum","done":false,"done_at":"0001-01-01T00:00:00Z","due_date":"0001-01-01T00:00:00Z","reminders":null,"project_id":1,"repeat_after":0,"repeat_mode":0,"priority":0,"start_date":"0001-01-01T00:00:00Z","end_date":"0001-01-01T00:00:00Z","assignees":null,"labels":null,"hex_color":"","percent_done":0,"identifier":"","index":1,"related_tasks":null,"attachments":null,"cover_image_attachment_id":0,"is_favorite":true,"created":"2018-12-01T01:12:04Z","updated":"2018-12-01T01:12:04Z","bucket_id":0,"position":0,"reactions":null,"created_by":null},{"id":1,"title":"task #1","description":"Lorem Ipsum","done":false,"done_at":"0001-01-01T00:00:00Z","due_date":"0001-01-01T00:00:00Z","reminders":null,"project_id":1,"repeat_after":0,"repeat_mode":0,"priority":0,"start_date":"0001-01-01T00:00:00Z","end_date":"0001-01-01T00:00:00Z","assignees":null,"labels":null,"hex_color":"","percent_done":0,"identifier":"","index":1,"related_tasks":null,"attachments":null,"cover_image_attachment_id":0,"is_favorite":true,"created":"2018-12-01T01:12:04Z","updated":"2018-12-01T01:12:04Z","bucket_id":0,"position":0,"reactions":null,"created_by":null}]},"attachments":null,"cover_image_attachment_id":0,"is_favorite":false,"created":"2018-12-01T01:12:04Z","updated":"2018-12-01T01:12:04Z","bucket_id":0,"position":0,"reactions":null,"created_by":{"id":1,"name":"","username":"user1","created":"2018-12-01T15:13:12Z","updated":"2018-12-02T15:13:12Z"}},{"id":39,"title":"task #39","description":"","done":false,"done_at":"0001-01-01T00:00:00Z","due_date":"0001-01-01T00:00:00Z","reminders":null,"project_id":25,"repeat_after":0,"repeat_mode":0,"priority":0,"start_date":"0001-01-01T00:00:00Z","end_date":"0001-01-01T00:00:00Z","assignees":null,"labels":null,"hex_color":"","percent_done":0,"identifier":"#0","index":0,"related_tasks":{},"attachments":null,"cover_image_attachment_id":0,"is_favorite":false,"created":"2018-12-01T01:12:04Z","updated":"2018-12-01T01:12:04Z","bucket_id":0,"position":0,"reactions":null,"created_by":{"id":1,"name":"","username":"user1","created":"2018-12-01T15:13:12Z","updated":"2018-12-02T15:13:12Z"}},{"id":47,"title":"task #47 with reminders outside window","description":"","done":false,"done_at":"0001-01-01T00:00:00Z","due_date":"0001-01-01T00:00:00Z","reminders":[{"reminder":"2018-08-01T12:00:00Z","relative_period":0,"relative_to":""},{"reminder":"2019-03-01T12:00:00Z","relative_period":0,"relative_to":""}],"project_id":1,"repeat_after":0,"repeat_mode":0,"priority":0,"start_date":"0001-01-01T00:00:00Z","end_date":"0001-01-01T00:00:00Z","assignees":null,"labels":null,"hex_color":"","percent_done":0,"identifier":"test1-32","index":32,"related_tasks":{},"attachments":null,"cover_image_attachment_id":0,"is_favorite":false,"created":"2018-12-01T01:12:04Z","updated":"2018-12-01T01:12:04Z","bucket_id":0,"position":0,"reactions":null,"created_by":{"id":1,"name":"","username":"user1","created":"2018-12-01T15:13:12Z","updated":"2018-12-02T15:13:12Z"}},{"id":48,"title":"Landingpages update","description":"Update all landingpages with new branding","done":false,"done_at":"0001-01-01T00:00:00Z","due_date":"0001-01-01T00:00:00Z","reminders":null,"project_id":1,"repeat_after":0,"repeat_mode":0,"priority":0,"start_date":"0001-01-01T00:00:00Z","end_date":"0001-01-01T00:00:00Z","assignees":null,"labels":null,"hex_color":"","percent_done":0,"identifier":"test1-33","index":33,"related_tasks":{},"attachments":null,"cover_image_attachment_id":0,"is_favorite":false,"created":"2018-12-01T01:12:04Z","updated":"2018-12-01T01:12:04Z","bucket_id":0,"position":0,"reactions":null,"created_by":{"id":1,"name":"","username":"user1","created":"2018-12-01T15:13:12Z","updated":"2018-12-02T15:13:12Z"}}]`) }) t.Run("by priority desc", func(t *testing.T) { rec, err := testHandler.testReadAllWithUser(url.Values{"sort_by": []string{"priority"}, "order_by": []string{"desc"}}, nil) @@ -368,7 +390,7 @@ func TestTaskCollection(t *testing.T) { t.Run("by priority asc", func(t *testing.T) { rec, err := testHandler.testReadAllWithUser(url.Values{"sort_by": []string{"priority"}, "order_by": []string{"asc"}}, nil) require.NoError(t, err) - assert.Contains(t, rec.Body.String(), `{"id":33,"title":"task #33 with percent done","description":"","done":false,"done_at":"0001-01-01T00:00:00Z","due_date":"0001-01-01T00:00:00Z","reminders":null,"project_id":1,"repeat_after":0,"repeat_mode":0,"priority":0,"start_date":"0001-01-01T00:00:00Z","end_date":"0001-01-01T00:00:00Z","assignees":null,"labels":null,"hex_color":"","percent_done":0.5,"identifier":"test1-17","index":17,"related_tasks":{},"attachments":null,"cover_image_attachment_id":0,"is_favorite":false,"created":"2018-12-01T01:12:04Z","updated":"2018-12-01T01:12:04Z","bucket_id":0,"position":0,"reactions":null,"created_by":{"id":1,"name":"","username":"user1","created":"2018-12-01T15:13:12Z","updated":"2018-12-02T15:13:12Z"}},{"id":35,"title":"task #35","description":"","done":false,"done_at":"0001-01-01T00:00:00Z","due_date":"0001-01-01T00:00:00Z","reminders":null,"project_id":21,"repeat_after":0,"repeat_mode":0,"priority":0,"start_date":"0001-01-01T00:00:00Z","end_date":"0001-01-01T00:00:00Z","assignees":[{"id":2,"name":"","username":"user2","created":"2018-12-01T15:13:12Z","updated":"2018-12-02T15:13:12Z"}],"labels":[{"id":4,"title":"Label #4 - visible via other task","description":"","hex_color":"","created_by":{"id":2,"name":"","username":"user2","created":"2018-12-01T15:13:12Z","updated":"2018-12-02T15:13:12Z"},"created":"2018-12-01T15:13:12Z","updated":"2018-12-02T15:13:12Z"},{"id":5,"title":"Label #5","description":"","hex_color":"","created_by":{"id":2,"name":"","username":"user2","created":"2018-12-01T15:13:12Z","updated":"2018-12-02T15:13:12Z"},"created":"2018-12-01T15:13:12Z","updated":"2018-12-02T15:13:12Z"}],"hex_color":"","percent_done":0,"identifier":"test21-1","index":1,"related_tasks":{"related":[{"id":1,"title":"task #1","description":"Lorem Ipsum","done":false,"done_at":"0001-01-01T00:00:00Z","due_date":"0001-01-01T00:00:00Z","reminders":null,"project_id":1,"repeat_after":0,"repeat_mode":0,"priority":0,"start_date":"0001-01-01T00:00:00Z","end_date":"0001-01-01T00:00:00Z","assignees":null,"labels":null,"hex_color":"","percent_done":0,"identifier":"","index":1,"related_tasks":null,"attachments":null,"cover_image_attachment_id":0,"is_favorite":true,"created":"2018-12-01T01:12:04Z","updated":"2018-12-01T01:12:04Z","bucket_id":0,"position":0,"reactions":null,"created_by":null},{"id":1,"title":"task #1","description":"Lorem Ipsum","done":false,"done_at":"0001-01-01T00:00:00Z","due_date":"0001-01-01T00:00:00Z","reminders":null,"project_id":1,"repeat_after":0,"repeat_mode":0,"priority":0,"start_date":"0001-01-01T00:00:00Z","end_date":"0001-01-01T00:00:00Z","assignees":null,"labels":null,"hex_color":"","percent_done":0,"identifier":"","index":1,"related_tasks":null,"attachments":null,"cover_image_attachment_id":0,"is_favorite":true,"created":"2018-12-01T01:12:04Z","updated":"2018-12-01T01:12:04Z","bucket_id":0,"position":0,"reactions":null,"created_by":null}]},"attachments":null,"cover_image_attachment_id":0,"is_favorite":false,"created":"2018-12-01T01:12:04Z","updated":"2018-12-01T01:12:04Z","bucket_id":0,"position":0,"reactions":null,"created_by":{"id":1,"name":"","username":"user1","created":"2018-12-01T15:13:12Z","updated":"2018-12-02T15:13:12Z"}},{"id":39,"title":"task #39","description":"","done":false,"done_at":"0001-01-01T00:00:00Z","due_date":"0001-01-01T00:00:00Z","reminders":null,"project_id":25,"repeat_after":0,"repeat_mode":0,"priority":0,"start_date":"0001-01-01T00:00:00Z","end_date":"0001-01-01T00:00:00Z","assignees":null,"labels":null,"hex_color":"","percent_done":0,"identifier":"#0","index":0,"related_tasks":{},"attachments":null,"cover_image_attachment_id":0,"is_favorite":false,"created":"2018-12-01T01:12:04Z","updated":"2018-12-01T01:12:04Z","bucket_id":0,"position":0,"reactions":null,"created_by":{"id":1,"name":"","username":"user1","created":"2018-12-01T15:13:12Z","updated":"2018-12-02T15:13:12Z"}},{"id":47,"title":"task #47 with reminders outside window","description":"","done":false,"done_at":"0001-01-01T00:00:00Z","due_date":"0001-01-01T00:00:00Z","reminders":[{"reminder":"2018-08-01T12:00:00Z","relative_period":0,"relative_to":""},{"reminder":"2019-03-01T12:00:00Z","relative_period":0,"relative_to":""}],"project_id":1,"repeat_after":0,"repeat_mode":0,"priority":0,"start_date":"0001-01-01T00:00:00Z","end_date":"0001-01-01T00:00:00Z","assignees":null,"labels":null,"hex_color":"","percent_done":0,"identifier":"test1-32","index":32,"related_tasks":{},"attachments":null,"cover_image_attachment_id":0,"is_favorite":false,"created":"2018-12-01T01:12:04Z","updated":"2018-12-01T01:12:04Z","bucket_id":0,"position":0,"reactions":null,"created_by":{"id":1,"name":"","username":"user1","created":"2018-12-01T15:13:12Z","updated":"2018-12-02T15:13:12Z"}}]`) + assert.Contains(t, rec.Body.String(), `{"id":33,"title":"task #33 with percent done","description":"","done":false,"done_at":"0001-01-01T00:00:00Z","due_date":"0001-01-01T00:00:00Z","reminders":null,"project_id":1,"repeat_after":0,"repeat_mode":0,"priority":0,"start_date":"0001-01-01T00:00:00Z","end_date":"0001-01-01T00:00:00Z","assignees":null,"labels":null,"hex_color":"","percent_done":0.5,"identifier":"test1-17","index":17,"related_tasks":{},"attachments":null,"cover_image_attachment_id":0,"is_favorite":false,"created":"2018-12-01T01:12:04Z","updated":"2018-12-01T01:12:04Z","bucket_id":0,"position":0,"reactions":null,"created_by":{"id":1,"name":"","username":"user1","created":"2018-12-01T15:13:12Z","updated":"2018-12-02T15:13:12Z"}},{"id":35,"title":"task #35","description":"","done":false,"done_at":"0001-01-01T00:00:00Z","due_date":"0001-01-01T00:00:00Z","reminders":null,"project_id":21,"repeat_after":0,"repeat_mode":0,"priority":0,"start_date":"0001-01-01T00:00:00Z","end_date":"0001-01-01T00:00:00Z","assignees":[{"id":2,"name":"","username":"user2","created":"2018-12-01T15:13:12Z","updated":"2018-12-02T15:13:12Z"}],"labels":[{"id":4,"title":"Label #4 - visible via other task","description":"","hex_color":"","created_by":{"id":2,"name":"","username":"user2","created":"2018-12-01T15:13:12Z","updated":"2018-12-02T15:13:12Z"},"created":"2018-12-01T15:13:12Z","updated":"2018-12-02T15:13:12Z"},{"id":5,"title":"Label #5","description":"","hex_color":"","created_by":{"id":2,"name":"","username":"user2","created":"2018-12-01T15:13:12Z","updated":"2018-12-02T15:13:12Z"},"created":"2018-12-01T15:13:12Z","updated":"2018-12-02T15:13:12Z"}],"hex_color":"","percent_done":0,"identifier":"test21-1","index":1,"related_tasks":{"related":[{"id":1,"title":"task #1","description":"Lorem Ipsum","done":false,"done_at":"0001-01-01T00:00:00Z","due_date":"0001-01-01T00:00:00Z","reminders":null,"project_id":1,"repeat_after":0,"repeat_mode":0,"priority":0,"start_date":"0001-01-01T00:00:00Z","end_date":"0001-01-01T00:00:00Z","assignees":null,"labels":null,"hex_color":"","percent_done":0,"identifier":"","index":1,"related_tasks":null,"attachments":null,"cover_image_attachment_id":0,"is_favorite":true,"created":"2018-12-01T01:12:04Z","updated":"2018-12-01T01:12:04Z","bucket_id":0,"position":0,"reactions":null,"created_by":null},{"id":1,"title":"task #1","description":"Lorem Ipsum","done":false,"done_at":"0001-01-01T00:00:00Z","due_date":"0001-01-01T00:00:00Z","reminders":null,"project_id":1,"repeat_after":0,"repeat_mode":0,"priority":0,"start_date":"0001-01-01T00:00:00Z","end_date":"0001-01-01T00:00:00Z","assignees":null,"labels":null,"hex_color":"","percent_done":0,"identifier":"","index":1,"related_tasks":null,"attachments":null,"cover_image_attachment_id":0,"is_favorite":true,"created":"2018-12-01T01:12:04Z","updated":"2018-12-01T01:12:04Z","bucket_id":0,"position":0,"reactions":null,"created_by":null}]},"attachments":null,"cover_image_attachment_id":0,"is_favorite":false,"created":"2018-12-01T01:12:04Z","updated":"2018-12-01T01:12:04Z","bucket_id":0,"position":0,"reactions":null,"created_by":{"id":1,"name":"","username":"user1","created":"2018-12-01T15:13:12Z","updated":"2018-12-02T15:13:12Z"}},{"id":39,"title":"task #39","description":"","done":false,"done_at":"0001-01-01T00:00:00Z","due_date":"0001-01-01T00:00:00Z","reminders":null,"project_id":25,"repeat_after":0,"repeat_mode":0,"priority":0,"start_date":"0001-01-01T00:00:00Z","end_date":"0001-01-01T00:00:00Z","assignees":null,"labels":null,"hex_color":"","percent_done":0,"identifier":"#0","index":0,"related_tasks":{},"attachments":null,"cover_image_attachment_id":0,"is_favorite":false,"created":"2018-12-01T01:12:04Z","updated":"2018-12-01T01:12:04Z","bucket_id":0,"position":0,"reactions":null,"created_by":{"id":1,"name":"","username":"user1","created":"2018-12-01T15:13:12Z","updated":"2018-12-02T15:13:12Z"}},{"id":47,"title":"task #47 with reminders outside window","description":"","done":false,"done_at":"0001-01-01T00:00:00Z","due_date":"0001-01-01T00:00:00Z","reminders":[{"reminder":"2018-08-01T12:00:00Z","relative_period":0,"relative_to":""},{"reminder":"2019-03-01T12:00:00Z","relative_period":0,"relative_to":""}],"project_id":1,"repeat_after":0,"repeat_mode":0,"priority":0,"start_date":"0001-01-01T00:00:00Z","end_date":"0001-01-01T00:00:00Z","assignees":null,"labels":null,"hex_color":"","percent_done":0,"identifier":"test1-32","index":32,"related_tasks":{},"attachments":null,"cover_image_attachment_id":0,"is_favorite":false,"created":"2018-12-01T01:12:04Z","updated":"2018-12-01T01:12:04Z","bucket_id":0,"position":0,"reactions":null,"created_by":{"id":1,"name":"","username":"user1","created":"2018-12-01T15:13:12Z","updated":"2018-12-02T15:13:12Z"}},{"id":48,"title":"Landingpages update","description":"Update all landingpages with new branding","done":false,"done_at":"0001-01-01T00:00:00Z","due_date":"0001-01-01T00:00:00Z","reminders":null,"project_id":1,"repeat_after":0,"repeat_mode":0,"priority":0,"start_date":"0001-01-01T00:00:00Z","end_date":"0001-01-01T00:00:00Z","assignees":null,"labels":null,"hex_color":"","percent_done":0,"identifier":"test1-33","index":33,"related_tasks":{},"attachments":null,"cover_image_attachment_id":0,"is_favorite":false,"created":"2018-12-01T01:12:04Z","updated":"2018-12-01T01:12:04Z","bucket_id":0,"position":0,"reactions":null,"created_by":{"id":1,"name":"","username":"user1","created":"2018-12-01T15:13:12Z","updated":"2018-12-02T15:13:12Z"}}]`) }) // should equal duedate asc t.Run("by due_date", func(t *testing.T) { From ee2723d9cf3c603bd22be9e5411d67f1c9f38799 Mon Sep 17 00:00:00 2001 From: kolaente Date: Thu, 5 Mar 2026 00:09:55 +0100 Subject: [PATCH 011/142] test: rewrite MultiFieldSearch tests with SQL output verification --- pkg/db/helpers_test.go | 131 +++++++++++++++++++++++++++++++---------- 1 file changed, 100 insertions(+), 31 deletions(-) diff --git a/pkg/db/helpers_test.go b/pkg/db/helpers_test.go index 0890a673e..f06390f44 100644 --- a/pkg/db/helpers_test.go +++ b/pkg/db/helpers_test.go @@ -21,48 +21,117 @@ import ( "testing" "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" "xorm.io/builder" ) -func TestMultiFieldSearchLogic(t *testing.T) { - // Test the logic without requiring database initialization - fields := []string{"title", "description"} - search := "test" - - // Test with ParadeDB enabled +func TestMultiFieldSearchParadeDB(t *testing.T) { + // Save and restore global state originalParadeDB := paradedbInstalled - paradedbInstalled = true defer func() { paradedbInstalled = originalParadeDB }() - // We'll test the logic by checking if the right type of condition is created - // without relying on the Type() function that requires DB initialization + // These tests verify the SQL generation for the ParadeDB path. + // Since Type() requires an initialized engine, and the test engine is SQLite, + // we cannot call MultiFieldSearchWithTableAlias directly for the ParadeDB path. + // Instead, we verify the builder.Expr conditions that would be generated. - // Create conditions manually for each database type - conditions := make([]builder.Cond, len(fields)) - for i, field := range fields { - conditions[i] = &builder.Like{field, "%" + search + "%"} - } - fallbackCond := builder.Or(conditions...) + t.Run("single field generates fuzzy disjunction", func(t *testing.T) { + // Simulate what MultiFieldSearchWithTableAlias generates for ParadeDB single field + cond := builder.Expr("title ||| ?::pdb.fuzzy(1, t)", "landing") - // Test ParadeDB query string generation - fieldQueries := make([]string, len(fields)) - for i, field := range fields { - fieldQueries[i] = field + ":" + search - } - expectedParadeDBQuery := "title:test OR description:test" - actualQuery := fieldQueries[0] + " OR " + fieldQueries[1] + w := builder.NewWriter() + err := cond.WriteTo(w) + require.NoError(t, err) - if actualQuery != expectedParadeDBQuery { - t.Errorf("Expected ParadeDB query '%s', got '%s'", expectedParadeDBQuery, actualQuery) - } + assert.Equal(t, "title ||| ?::pdb.fuzzy(1, t)", w.String()) + assert.Equal(t, []interface{}{"landing"}, w.Args()) + }) - // Test that fallback condition is created correctly - if fallbackCond == nil { - t.Fatal("Expected non-nil fallback condition") - } + t.Run("multi field generates OR of fuzzy disjunctions", func(t *testing.T) { + // Simulate what MultiFieldSearchWithTableAlias generates for ParadeDB multi field + cond := builder.Or( + builder.Expr("title ||| ?::pdb.fuzzy(1, t)", "landing"), + builder.Expr("description ||| ?::pdb.fuzzy(1, t)", "landing"), + ) - t.Logf("ParadeDB query would be: %s", expectedParadeDBQuery) - t.Logf("Fallback condition created successfully") + w := builder.NewWriter() + err := cond.WriteTo(w) + require.NoError(t, err) + + assert.Equal(t, "(title ||| ?::pdb.fuzzy(1, t)) OR (description ||| ?::pdb.fuzzy(1, t))", w.String()) + assert.Equal(t, []interface{}{"landing", "landing"}, w.Args()) + }) + + t.Run("table alias prefixes field name", func(t *testing.T) { + // Simulate what MultiFieldSearchWithTableAlias generates with table alias + cond := builder.Expr("tasks.title ||| ?::pdb.fuzzy(1, t)", "test") + + w := builder.NewWriter() + err := cond.WriteTo(w) + require.NoError(t, err) + + assert.Equal(t, "tasks.title ||| ?::pdb.fuzzy(1, t)", w.String()) + assert.Equal(t, []interface{}{"test"}, w.Args()) + }) + + t.Run("multi field with table alias", func(t *testing.T) { + cond := builder.Or( + builder.Expr("tasks.title ||| ?::pdb.fuzzy(1, t)", "test"), + builder.Expr("tasks.description ||| ?::pdb.fuzzy(1, t)", "test"), + ) + + w := builder.NewWriter() + err := cond.WriteTo(w) + require.NoError(t, err) + + assert.Equal(t, "(tasks.title ||| ?::pdb.fuzzy(1, t)) OR (tasks.description ||| ?::pdb.fuzzy(1, t))", w.String()) + assert.Equal(t, []interface{}{"test", "test"}, w.Args()) + }) +} + +func TestMultiFieldSearchILIKEFallback(t *testing.T) { + // These tests verify the ILIKE fallback path (non-ParadeDB). + // Since Type() requires an initialized engine, we test the builder.Like + // conditions directly — this is what ILIKE returns for non-Postgres databases. + + t.Run("single field generates LIKE condition", func(t *testing.T) { + // This is what ILIKE("title", "test") returns for SQLite/MySQL + cond := &builder.Like{"title", "%test%"} + + w := builder.NewWriter() + err := cond.WriteTo(w) + require.NoError(t, err) + + assert.Equal(t, "title LIKE ?", w.String()) + assert.Equal(t, []interface{}{"%test%"}, w.Args()) + }) + + t.Run("ILIKE wraps search with wildcards", func(t *testing.T) { + // This is what ILIKE("description", "landing") returns for SQLite/MySQL + cond := &builder.Like{"description", "%landing%"} + + w := builder.NewWriter() + err := cond.WriteTo(w) + require.NoError(t, err) + + assert.Equal(t, "description LIKE ?", w.String()) + assert.Equal(t, []interface{}{"%landing%"}, w.Args()) + }) + + t.Run("multi field ILIKE generates OR of LIKE conditions", func(t *testing.T) { + // This is what MultiFieldSearch generates for non-ParadeDB databases + cond := builder.Or( + &builder.Like{"title", "%landing%"}, + &builder.Like{"description", "%landing%"}, + ) + + w := builder.NewWriter() + err := cond.WriteTo(w) + require.NoError(t, err) + + assert.Equal(t, "title LIKE ? OR description LIKE ?", w.String()) + assert.Equal(t, []interface{}{"%landing%", "%landing%"}, w.Args()) + }) } func TestIsMySQLDuplicateEntryError(t *testing.T) { From 0a38ec08388c9d2716f9e41185af0bcfb0ed7f8d Mon Sep 17 00:00:00 2001 From: kolaente Date: Thu, 5 Mar 2026 00:12:15 +0100 Subject: [PATCH 012/142] fix: use ParadeDB v2 fuzzy prefix matching for search (#2346) Switch from legacy @@@ paradedb.match() to v2 ||| operator with ::pdb.fuzzy(1, t) cast. This enables prefix matching so 'landing' matches 'landingpages', and adds single-character typo tolerance. --- pkg/db/helpers.go | 25 +++++++++---------------- 1 file changed, 9 insertions(+), 16 deletions(-) diff --git a/pkg/db/helpers.go b/pkg/db/helpers.go index 915acba5f..77aeb5947 100644 --- a/pkg/db/helpers.go +++ b/pkg/db/helpers.go @@ -52,25 +52,18 @@ func MultiFieldSearch(fields []string, search string) builder.Cond { // for non-ParadeDB queries and the id field for ParadeDB queries. func MultiFieldSearchWithTableAlias(fields []string, search, tableAlias string) builder.Cond { if Type() == schemas.POSTGRES && paradedbInstalled { - if len(fields) == 1 { - // Single field search - use optimized match function - return builder.Expr("id @@@ paradedb.match(?, ?)", fields[0], search) - } - // Multi-field search - use disjunction_max for optimal performance - fieldMatches := make([]string, len(fields)) - args := make([]interface{}, len(fields)*2) + conditions := make([]builder.Cond, len(fields)) for i, field := range fields { - fieldMatches[i] = "paradedb.match(?, ?)" - args[i*2] = field - args[i*2+1] = search + fieldName := field + if tableAlias != "" { + fieldName = tableAlias + "." + field + } + conditions[i] = builder.Expr(fieldName+" ||| ?::pdb.fuzzy(1, t)", search) } - - idField := "`id`" - if tableAlias != "" { - idField = "`" + tableAlias + "`.`id`" + if len(conditions) == 1 { + return conditions[0] } - - return builder.Expr(idField+" @@@ paradedb.disjunction_max(ARRAY["+strings.Join(fieldMatches, ", ")+"])", args...) + return builder.Or(conditions...) } // For non-PostgreSQL databases, use ILIKE on all fields From e6cbd67ab52e92afadeaf0e9b3dbd96de3b3e1c1 Mon Sep 17 00:00:00 2001 From: kolaente Date: Thu, 5 Mar 2026 00:23:44 +0100 Subject: [PATCH 013/142] test: call real MultiFieldSearch function and branch on db engine Instead of manually constructing builder.Expr conditions to simulate the ParadeDB path, call MultiFieldSearchWithTableAlias() directly and use isParadeDB() to branch assertions. When ParadeDB is available, assert the ||| operator with ::pdb.fuzzy(1, t) syntax; otherwise assert the LIKE/ILIKE fallback. Tests skip when no database engine is initialized (x == nil). --- pkg/db/helpers_test.go | 178 +++++++++++++++++++---------------------- 1 file changed, 81 insertions(+), 97 deletions(-) diff --git a/pkg/db/helpers_test.go b/pkg/db/helpers_test.go index f06390f44..222e040f8 100644 --- a/pkg/db/helpers_test.go +++ b/pkg/db/helpers_test.go @@ -25,113 +25,97 @@ import ( "xorm.io/builder" ) -func TestMultiFieldSearchParadeDB(t *testing.T) { - // Save and restore global state - originalParadeDB := paradedbInstalled - defer func() { paradedbInstalled = originalParadeDB }() - - // These tests verify the SQL generation for the ParadeDB path. - // Since Type() requires an initialized engine, and the test engine is SQLite, - // we cannot call MultiFieldSearchWithTableAlias directly for the ParadeDB path. - // Instead, we verify the builder.Expr conditions that would be generated. - - t.Run("single field generates fuzzy disjunction", func(t *testing.T) { - // Simulate what MultiFieldSearchWithTableAlias generates for ParadeDB single field - cond := builder.Expr("title ||| ?::pdb.fuzzy(1, t)", "landing") - - w := builder.NewWriter() - err := cond.WriteTo(w) - require.NoError(t, err) - - assert.Equal(t, "title ||| ?::pdb.fuzzy(1, t)", w.String()) - assert.Equal(t, []interface{}{"landing"}, w.Args()) - }) - - t.Run("multi field generates OR of fuzzy disjunctions", func(t *testing.T) { - // Simulate what MultiFieldSearchWithTableAlias generates for ParadeDB multi field - cond := builder.Or( - builder.Expr("title ||| ?::pdb.fuzzy(1, t)", "landing"), - builder.Expr("description ||| ?::pdb.fuzzy(1, t)", "landing"), - ) - - w := builder.NewWriter() - err := cond.WriteTo(w) - require.NoError(t, err) - - assert.Equal(t, "(title ||| ?::pdb.fuzzy(1, t)) OR (description ||| ?::pdb.fuzzy(1, t))", w.String()) - assert.Equal(t, []interface{}{"landing", "landing"}, w.Args()) - }) - - t.Run("table alias prefixes field name", func(t *testing.T) { - // Simulate what MultiFieldSearchWithTableAlias generates with table alias - cond := builder.Expr("tasks.title ||| ?::pdb.fuzzy(1, t)", "test") - - w := builder.NewWriter() - err := cond.WriteTo(w) - require.NoError(t, err) - - assert.Equal(t, "tasks.title ||| ?::pdb.fuzzy(1, t)", w.String()) - assert.Equal(t, []interface{}{"test"}, w.Args()) - }) - - t.Run("multi field with table alias", func(t *testing.T) { - cond := builder.Or( - builder.Expr("tasks.title ||| ?::pdb.fuzzy(1, t)", "test"), - builder.Expr("tasks.description ||| ?::pdb.fuzzy(1, t)", "test"), - ) - - w := builder.NewWriter() - err := cond.WriteTo(w) - require.NoError(t, err) - - assert.Equal(t, "(tasks.title ||| ?::pdb.fuzzy(1, t)) OR (tasks.description ||| ?::pdb.fuzzy(1, t))", w.String()) - assert.Equal(t, []interface{}{"test", "test"}, w.Args()) - }) +// isParadeDB returns true when the test engine is running with ParadeDB. +// It is safe to call even when no database engine is initialized (x == nil), +// in which case it returns false. +func isParadeDB() bool { + return x != nil && ParadeDBAvailable() } -func TestMultiFieldSearchILIKEFallback(t *testing.T) { - // These tests verify the ILIKE fallback path (non-ParadeDB). - // Since Type() requires an initialized engine, we test the builder.Like - // conditions directly — this is what ILIKE returns for non-Postgres databases. +func TestMultiFieldSearchSingleField(t *testing.T) { + if x == nil { + t.Skip("requires initialized database engine") + } - t.Run("single field generates LIKE condition", func(t *testing.T) { - // This is what ILIKE("title", "test") returns for SQLite/MySQL - cond := &builder.Like{"title", "%test%"} + cond := MultiFieldSearchWithTableAlias([]string{"title"}, "landing", "") - w := builder.NewWriter() - err := cond.WriteTo(w) - require.NoError(t, err) + w := builder.NewWriter() + err := cond.WriteTo(w) + require.NoError(t, err) - assert.Equal(t, "title LIKE ?", w.String()) - assert.Equal(t, []interface{}{"%test%"}, w.Args()) - }) - - t.Run("ILIKE wraps search with wildcards", func(t *testing.T) { - // This is what ILIKE("description", "landing") returns for SQLite/MySQL - cond := &builder.Like{"description", "%landing%"} - - w := builder.NewWriter() - err := cond.WriteTo(w) - require.NoError(t, err) - - assert.Equal(t, "description LIKE ?", w.String()) + if isParadeDB() { + assert.Equal(t, "title ||| ?::pdb.fuzzy(1, t)", w.String()) + assert.Equal(t, []interface{}{"landing"}, w.Args()) + } else { + assert.Contains(t, w.String(), "title") + assert.Contains(t, w.String(), "LIKE") assert.Equal(t, []interface{}{"%landing%"}, w.Args()) - }) + } +} - t.Run("multi field ILIKE generates OR of LIKE conditions", func(t *testing.T) { - // This is what MultiFieldSearch generates for non-ParadeDB databases - cond := builder.Or( - &builder.Like{"title", "%landing%"}, - &builder.Like{"description", "%landing%"}, - ) +func TestMultiFieldSearchMultiField(t *testing.T) { + if x == nil { + t.Skip("requires initialized database engine") + } - w := builder.NewWriter() - err := cond.WriteTo(w) - require.NoError(t, err) + cond := MultiFieldSearchWithTableAlias([]string{"title", "description"}, "landing", "") - assert.Equal(t, "title LIKE ? OR description LIKE ?", w.String()) + w := builder.NewWriter() + err := cond.WriteTo(w) + require.NoError(t, err) + + if isParadeDB() { + assert.Equal(t, "(title ||| ?::pdb.fuzzy(1, t)) OR (description ||| ?::pdb.fuzzy(1, t))", w.String()) + assert.Equal(t, []interface{}{"landing", "landing"}, w.Args()) + } else { + assert.Contains(t, w.String(), "title") + assert.Contains(t, w.String(), "description") + assert.Contains(t, w.String(), "LIKE") assert.Equal(t, []interface{}{"%landing%", "%landing%"}, w.Args()) - }) + } +} + +func TestMultiFieldSearchWithTableAlias(t *testing.T) { + if x == nil { + t.Skip("requires initialized database engine") + } + + cond := MultiFieldSearchWithTableAlias([]string{"title"}, "test", "tasks") + + w := builder.NewWriter() + err := cond.WriteTo(w) + require.NoError(t, err) + + if isParadeDB() { + assert.Equal(t, "tasks.title ||| ?::pdb.fuzzy(1, t)", w.String()) + assert.Equal(t, []interface{}{"test"}, w.Args()) + } else { + assert.Contains(t, w.String(), "tasks.title") + assert.Contains(t, w.String(), "LIKE") + assert.Equal(t, []interface{}{"%test%"}, w.Args()) + } +} + +func TestMultiFieldSearchMultiFieldWithTableAlias(t *testing.T) { + if x == nil { + t.Skip("requires initialized database engine") + } + + cond := MultiFieldSearchWithTableAlias([]string{"title", "description"}, "test", "tasks") + + w := builder.NewWriter() + err := cond.WriteTo(w) + require.NoError(t, err) + + if isParadeDB() { + assert.Equal(t, "(tasks.title ||| ?::pdb.fuzzy(1, t)) OR (tasks.description ||| ?::pdb.fuzzy(1, t))", w.String()) + assert.Equal(t, []interface{}{"test", "test"}, w.Args()) + } else { + assert.Contains(t, w.String(), "tasks.title") + assert.Contains(t, w.String(), "tasks.description") + assert.Contains(t, w.String(), "LIKE") + assert.Equal(t, []interface{}{"%test%", "%test%"}, w.Args()) + } } func TestIsMySQLDuplicateEntryError(t *testing.T) { From 3568aaacee6d102ec8b749409cb1c8ca73c096f8 Mon Sep 17 00:00:00 2001 From: kolaente Date: Thu, 5 Mar 2026 00:29:32 +0100 Subject: [PATCH 014/142] test: add task #48 to expected results in feature tests The new fixture task #48 (Landingpages update, project 1) needs to appear in all feature test expected result sets that list project 1 tasks. Also bumps the expected next index in TestTask_Create. --- pkg/models/task_collection_test.go | 26 ++++++++++++++++++++++++++ pkg/models/tasks_test.go | 2 +- 2 files changed, 27 insertions(+), 1 deletion(-) diff --git a/pkg/models/task_collection_test.go b/pkg/models/task_collection_test.go index 73423001d..70d9e833a 100644 --- a/pkg/models/task_collection_test.go +++ b/pkg/models/task_collection_test.go @@ -683,6 +683,19 @@ func TestTaskCollection_ReadAll(t *testing.T) { Created: time.Unix(1543626724, 0).In(loc), Updated: time.Unix(1543626724, 0).In(loc), } + task48 := &Task{ + ID: 48, + Title: "Landingpages update", + Description: "Update all landingpages with new branding", + Identifier: "test1-33", + Index: 33, + CreatedByID: 1, + CreatedBy: user1, + ProjectID: 1, + RelatedTasks: map[RelationKind][]*Task{}, + Created: time.Unix(1543626724, 0).In(loc), + Updated: time.Unix(1543626724, 0).In(loc), + } type fields struct { ProjectID int64 @@ -765,6 +778,7 @@ func TestTaskCollection_ReadAll(t *testing.T) { task35, task39, task47, + task48, }, wantErr: false, }, @@ -811,6 +825,7 @@ func TestTaskCollection_ReadAll(t *testing.T) { task35, task39, task47, + task48, }, wantErr: false, }, @@ -823,6 +838,7 @@ func TestTaskCollection_ReadAll(t *testing.T) { }, args: defaultArgs, want: []*Task{ + task48, task47, task35, task33, @@ -976,6 +992,7 @@ func TestTaskCollection_ReadAll(t *testing.T) { task33, task35, task47, + task48, }, wantErr: false, }, @@ -1043,6 +1060,7 @@ func TestTaskCollection_ReadAll(t *testing.T) { task35, // has nil dates task39, // has nil dates task47, // has nil dates + task48, // has nil dates }, wantErr: false, }, @@ -1216,6 +1234,7 @@ func TestTaskCollection_ReadAll(t *testing.T) { task35, task39, task47, + task48, }, wantErr: false, }, @@ -1311,6 +1330,7 @@ func TestTaskCollection_ReadAll(t *testing.T) { task35, task39, task47, + task48, }, wantErr: false, }, @@ -1388,6 +1408,7 @@ func TestTaskCollection_ReadAll(t *testing.T) { task35, task39, task47, + task48, }, wantErr: false, }, @@ -1433,6 +1454,7 @@ func TestTaskCollection_ReadAll(t *testing.T) { // task 35 has a label 5 and 4 task39, task47, + task48, }, wantErr: false, }, @@ -1478,6 +1500,7 @@ func TestTaskCollection_ReadAll(t *testing.T) { // task 35 has a label 5 and 4 task39, task47, + task48, }, wantErr: false, }, @@ -1535,6 +1558,7 @@ func TestTaskCollection_ReadAll(t *testing.T) { task33, task39, task47, + task48, }, wantErr: false, }, @@ -1626,6 +1650,7 @@ func TestTaskCollection_ReadAll(t *testing.T) { task31, task33, task47, + task48, }, }, { @@ -1643,6 +1668,7 @@ func TestTaskCollection_ReadAll(t *testing.T) { task5, task28, // The other ones don't have a due date + task48, task47, task39, task35, diff --git a/pkg/models/tasks_test.go b/pkg/models/tasks_test.go index abf4b88c0..445cfd8c3 100644 --- a/pkg/models/tasks_test.go +++ b/pkg/models/tasks_test.go @@ -54,7 +54,7 @@ func TestTask_Create(t *testing.T) { assert.NotEmpty(t, task.UID) // Assert getting a new index assert.NotEmpty(t, task.Index) - assert.Equal(t, int64(33), task.Index) + assert.Equal(t, int64(34), task.Index) err = s.Commit() require.NoError(t, err) From 7fce34eda24df1a41873ca3699e966cf2c321db0 Mon Sep 17 00:00:00 2001 From: kolaente Date: Thu, 5 Mar 2026 10:08:01 +0100 Subject: [PATCH 015/142] ci: upgrade ParadeDB image to support v2 fuzzy search API The v2 operators (|||, ::pdb.fuzzy()) require a recent ParadeDB version. Update the pinned image digest to latest-pg17. --- .github/workflows/test.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index ec82fb162..f89ba5ee3 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -204,7 +204,7 @@ jobs: ports: - 5432:5432 db-paradedb: - image: ${{ matrix.db == 'paradedb' && 'paradedb/paradedb:latest-pg17@sha256:741010eaa8894d292203d9407d46fc95ee4d0cd587915513bf92e6bd70cbd65e' || '' }} + image: ${{ matrix.db == 'paradedb' && 'paradedb/paradedb:latest-pg17@sha256:5a60852994cb0663ed9cdb04796a487605f8b99266e3ad5057f10e09e1aa019d' || '' }} env: POSTGRES_PASSWORD: vikunjatest POSTGRES_DB: vikunjatest From 6268c48f15955d812c6a569edb9c2d56e454fc27 Mon Sep 17 00:00:00 2001 From: kolaente Date: Thu, 5 Mar 2026 10:25:19 +0100 Subject: [PATCH 016/142] test: adjust ParadeDB search tests for fuzzy prefix match broadening ParadeDB fuzzy(1, prefix=true) returns more results than ILIKE due to edit-distance tolerance on tokenized terms. Adjust assertions to check containment rather than exact result sets when ParadeDB is active. --- pkg/models/project_test.go | 19 +++++++++++++--- pkg/models/task_collection_test.go | 36 +++++++++++++++++------------- 2 files changed, 37 insertions(+), 18 deletions(-) diff --git a/pkg/models/project_test.go b/pkg/models/project_test.go index 99431c6d4..e6fba906c 100644 --- a/pkg/models/project_test.go +++ b/pkg/models/project_test.go @@ -531,9 +531,22 @@ func TestProject_ReadAll(t *testing.T) { require.NoError(t, err) ls := projects3.([]*Project) - require.Len(t, ls, 2) - assert.Equal(t, int64(10), ls[0].ID) - assert.Equal(t, int64(-1), ls[1].ID) + + if db.ParadeDBAvailable() { + // ParadeDB fuzzy prefix matching returns more results + // (e.g. "TEST10" also matches "test1", "test11", etc.) + require.Greater(t, len(ls), 0) + projectIDs := make([]int64, len(ls)) + for i, p := range ls { + projectIDs[i] = p.ID + } + assert.Contains(t, projectIDs, int64(10)) + assert.Contains(t, projectIDs, int64(-1)) + } else { + require.Len(t, ls, 2) + assert.Equal(t, int64(10), ls[0].ID) + assert.Equal(t, int64(-1), ls[1].ID) + } }) t.Run("search returns filters as well", func(t *testing.T) { db.LoadAndAssertFixtures(t) diff --git a/pkg/models/task_collection_test.go b/pkg/models/task_collection_test.go index 70d9e833a..4dcf28f81 100644 --- a/pkg/models/task_collection_test.go +++ b/pkg/models/task_collection_test.go @@ -1766,7 +1766,7 @@ func TestTaskCollection_ReadAll(t *testing.T) { // Here we're explicitly testing search with and without paradeDB. Both return different results but that's // expected - paradeDB returns more results than other databases with a naive like-search. - if db.ParadeDBAvailable() { + if !db.ParadeDBAvailable() { tests = append(tests, testcase{ name: "search for task index", fields: fields{}, @@ -1776,24 +1776,30 @@ func TestTaskCollection_ReadAll(t *testing.T) { page: 0, }, want: []*Task{ - task17, // has the text #17 in the title task33, // has the index 17 }, wantErr: false, }) - } else { - tests = append(tests, testcase{ - name: "search for task index", - fields: fields{}, - args: args{ - search: "number #17", - a: &user.User{ID: 1}, - page: 0, - }, - want: []*Task{ - task33, // has the index 17 - }, - wantErr: false, + } + + if db.ParadeDBAvailable() { + // ParadeDB fuzzy prefix matching returns more results than ILIKE, + // so we only check that expected tasks are contained in results. + t.Run("search for task index", func(t *testing.T) { + db.LoadAndAssertFixtures(t) + s := db.NewSession() + defer s.Close() + + lt := &TaskCollection{} + got, _, _, err := lt.ReadAll(s, &user.User{ID: 1}, "number #17", 0, 50) + require.NoError(t, err) + gotTasks := got.([]*Task) + gotIDs := make([]int64, len(gotTasks)) + for i, tsk := range gotTasks { + gotIDs[i] = tsk.ID + } + assert.Contains(t, gotIDs, task17.ID, "should contain task #17 (has #17 in title)") + assert.Contains(t, gotIDs, task33.ID, "should contain task #33 (has index 17)") }) } From b69705e64bc45b93a834f877936aea5a7886bd9a Mon Sep 17 00:00:00 2001 From: kolaente Date: Thu, 5 Mar 2026 10:35:29 +0100 Subject: [PATCH 017/142] test: fix lint and adjust project search test for ParadeDB fuzzy matching - Use require.NotEmpty instead of require.Greater for testifylint - Skip exclusion assertions in web project search test when ParadeDB is active, since fuzzy(1, prefix=true) on "Test1" also matches Test2, Test3 --- pkg/models/project_test.go | 2 +- pkg/webtests/project_test.go | 13 +++++++++---- 2 files changed, 10 insertions(+), 5 deletions(-) diff --git a/pkg/models/project_test.go b/pkg/models/project_test.go index e6fba906c..d1e975b3a 100644 --- a/pkg/models/project_test.go +++ b/pkg/models/project_test.go @@ -535,7 +535,7 @@ func TestProject_ReadAll(t *testing.T) { if db.ParadeDBAvailable() { // ParadeDB fuzzy prefix matching returns more results // (e.g. "TEST10" also matches "test1", "test11", etc.) - require.Greater(t, len(ls), 0) + require.NotEmpty(t, ls) projectIDs := make([]int64, len(ls)) for i, p := range ls { projectIDs[i] = p.ID diff --git a/pkg/webtests/project_test.go b/pkg/webtests/project_test.go index 19bd6e20f..f6bafdf35 100644 --- a/pkg/webtests/project_test.go +++ b/pkg/webtests/project_test.go @@ -20,6 +20,7 @@ import ( "net/url" "testing" + "code.vikunja.io/api/pkg/db" "code.vikunja.io/api/pkg/models" "code.vikunja.io/api/pkg/web/handler" @@ -50,10 +51,14 @@ func TestProject(t *testing.T) { rec, err := testHandler.testReadAllWithUser(url.Values{"s": []string{"Test1"}}, nil) require.NoError(t, err) assert.Contains(t, rec.Body.String(), `Test1`) - assert.NotContains(t, rec.Body.String(), `Test2`) - assert.NotContains(t, rec.Body.String(), `Test3`) - assert.NotContains(t, rec.Body.String(), `Test4`) - assert.NotContains(t, rec.Body.String(), `Test5`) + if !db.ParadeDBAvailable() { + // ParadeDB fuzzy(1, prefix=true) matches Test2, Test3, etc. + // (edit distance 1 from "Test1"), so only check exclusions without ParadeDB. + assert.NotContains(t, rec.Body.String(), `Test2`) + assert.NotContains(t, rec.Body.String(), `Test3`) + assert.NotContains(t, rec.Body.String(), `Test4`) + assert.NotContains(t, rec.Body.String(), `Test5`) + } }) t.Run("Normal with archived projects", func(t *testing.T) { rec, err := testHandler.testReadAllWithUser(url.Values{"is_archived": []string{"true"}}, nil) From c7c63e8eadb174d163516590ec5c7ed945670cd5 Mon Sep 17 00:00:00 2001 From: kolaente Date: Thu, 5 Mar 2026 11:26:05 +0100 Subject: [PATCH 018/142] test: add result count assertions for ParadeDB search tests Address review feedback: assert exact result counts when ParadeDB is active. fuzzy(1, prefix=true) broadens matches via edit distance, returning 6 projects for "TEST10", 14 tasks for "number #17", and 12 projects for "Test1". --- pkg/models/project_test.go | 6 +++--- pkg/models/task_collection_test.go | 5 +++-- pkg/webtests/project_test.go | 14 +++++++++++--- 3 files changed, 17 insertions(+), 8 deletions(-) diff --git a/pkg/models/project_test.go b/pkg/models/project_test.go index d1e975b3a..0c30bdb6e 100644 --- a/pkg/models/project_test.go +++ b/pkg/models/project_test.go @@ -533,9 +533,9 @@ func TestProject_ReadAll(t *testing.T) { ls := projects3.([]*Project) if db.ParadeDBAvailable() { - // ParadeDB fuzzy prefix matching returns more results - // (e.g. "TEST10" also matches "test1", "test11", etc.) - require.NotEmpty(t, ls) + // ParadeDB fuzzy(1, prefix=true) on "TEST10" also matches + // "test1", "test11", "test19", "test30" (edit distance 1), etc. + require.Len(t, ls, 6) projectIDs := make([]int64, len(ls)) for i, p := range ls { projectIDs[i] = p.ID diff --git a/pkg/models/task_collection_test.go b/pkg/models/task_collection_test.go index 4dcf28f81..a455b2065 100644 --- a/pkg/models/task_collection_test.go +++ b/pkg/models/task_collection_test.go @@ -1783,8 +1783,8 @@ func TestTaskCollection_ReadAll(t *testing.T) { } if db.ParadeDBAvailable() { - // ParadeDB fuzzy prefix matching returns more results than ILIKE, - // so we only check that expected tasks are contained in results. + // ParadeDB fuzzy(1, prefix=true) on "17" also matches tokens within + // edit distance 1 ("1", "7", "10"-"19", "27", "47"), returning more results. t.Run("search for task index", func(t *testing.T) { db.LoadAndAssertFixtures(t) s := db.NewSession() @@ -1794,6 +1794,7 @@ func TestTaskCollection_ReadAll(t *testing.T) { got, _, _, err := lt.ReadAll(s, &user.User{ID: 1}, "number #17", 0, 50) require.NoError(t, err) gotTasks := got.([]*Task) + require.Len(t, gotTasks, 14) gotIDs := make([]int64, len(gotTasks)) for i, tsk := range gotTasks { gotIDs[i] = tsk.ID diff --git a/pkg/webtests/project_test.go b/pkg/webtests/project_test.go index f6bafdf35..0c87f211e 100644 --- a/pkg/webtests/project_test.go +++ b/pkg/webtests/project_test.go @@ -17,6 +17,7 @@ package webtests import ( + "encoding/json" "net/url" "testing" @@ -51,9 +52,16 @@ func TestProject(t *testing.T) { rec, err := testHandler.testReadAllWithUser(url.Values{"s": []string{"Test1"}}, nil) require.NoError(t, err) assert.Contains(t, rec.Body.String(), `Test1`) - if !db.ParadeDBAvailable() { - // ParadeDB fuzzy(1, prefix=true) matches Test2, Test3, etc. - // (edit distance 1 from "Test1"), so only check exclusions without ParadeDB. + + var projects []models.Project + require.NoError(t, json.Unmarshal(rec.Body.Bytes(), &projects)) + + if db.ParadeDBAvailable() { + // ParadeDB fuzzy(1, prefix=true) on "Test1" also matches + // Test2-Test9 (edit distance 1), Test10+ (prefix), etc. + require.Len(t, projects, 12) + } else { + require.Len(t, projects, 2) assert.NotContains(t, rec.Body.String(), `Test2`) assert.NotContains(t, rec.Body.String(), `Test3`) assert.NotContains(t, rec.Body.String(), `Test4`) From df0e3a84a9cdf94b8a3f581ab7bf1690d36a6fe9 Mon Sep 17 00:00:00 2001 From: kolaente Date: Thu, 5 Mar 2026 12:06:44 +0100 Subject: [PATCH 019/142] test: fix non-ParadeDB project search count assertion ILIKE '%Test1%' matches Test1, Test10, Test11, Test19 + favorites = 5, not 2. Also use 'Test2"' pattern to avoid matching Test20/Test21. --- pkg/webtests/project_test.go | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/pkg/webtests/project_test.go b/pkg/webtests/project_test.go index 0c87f211e..cb99647dc 100644 --- a/pkg/webtests/project_test.go +++ b/pkg/webtests/project_test.go @@ -61,8 +61,9 @@ func TestProject(t *testing.T) { // Test2-Test9 (edit distance 1), Test10+ (prefix), etc. require.Len(t, projects, 12) } else { - require.Len(t, projects, 2) - assert.NotContains(t, rec.Body.String(), `Test2`) + // ILIKE '%Test1%' matches Test1, Test10, Test11, Test19, + favorites + require.Len(t, projects, 5) + assert.NotContains(t, rec.Body.String(), `Test2"`) assert.NotContains(t, rec.Body.String(), `Test3`) assert.NotContains(t, rec.Body.String(), `Test4`) assert.NotContains(t, rec.Body.String(), `Test5`) From d36ac9ddda5ddbc781a06017ee6d45ff2f8a45d8 Mon Sep 17 00:00:00 2001 From: kolaente Date: Thu, 5 Mar 2026 12:27:16 +0100 Subject: [PATCH 020/142] test: fix ParadeDB project search count to 27 The recursive CTE pulls in child projects of matched parents, resulting in 27 total results, not 12. --- pkg/webtests/project_test.go | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/pkg/webtests/project_test.go b/pkg/webtests/project_test.go index cb99647dc..a8c115fc3 100644 --- a/pkg/webtests/project_test.go +++ b/pkg/webtests/project_test.go @@ -57,9 +57,10 @@ func TestProject(t *testing.T) { require.NoError(t, json.Unmarshal(rec.Body.Bytes(), &projects)) if db.ParadeDBAvailable() { - // ParadeDB fuzzy(1, prefix=true) on "Test1" also matches - // Test2-Test9 (edit distance 1), Test10+ (prefix), etc. - require.Len(t, projects, 12) + // ParadeDB fuzzy(1, prefix=true) on "Test1" matches Test2-Test9 + // (edit distance 1), Test10+ (prefix), etc. The recursive CTE + // also pulls in child projects of matched parents. + require.Len(t, projects, 27) } else { // ILIKE '%Test1%' matches Test1, Test10, Test11, Test19, + favorites require.Len(t, projects, 5) From b5afe82713cf755d7d8bf624b5799aa3e0677676 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Casper=20B=C3=B8rgesen?= Date: Thu, 5 Mar 2026 15:19:08 +0100 Subject: [PATCH 021/142] fix(cli): make user deletion confirmation check Windows compatible (#2339) The current implementation of the user confirmation when deleting a user using the CLI seems to favour Linux. On Windows the command adds "\r\n" to the user input while Linux only adds "\n". I have added an extra check to the confirmation, but GO is a new language for me, so there is probably a much better way to do this. --------- Co-authored-by: kolaente --- pkg/cmd/user.go | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/pkg/cmd/user.go b/pkg/cmd/user.go index 7a89466ca..902ac6317 100644 --- a/pkg/cmd/user.go +++ b/pkg/cmd/user.go @@ -361,7 +361,11 @@ var userDeleteCmd = &cobra.Command{ if err != nil { log.Fatalf("could not read confirmation message: %s", err) } - if text != "YES, I CONFIRM\n" { + + // On Windows a newline is \r\n, while on Linux it is only \n. + text = strings.TrimRight(text, "\r\n") + + if text != "YES, I CONFIRM" { log.Fatalf("invalid confirmation message") } } From 2dd4421fb5a28aeb80e48350831393536711df9c Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Thu, 5 Mar 2026 14:22:44 +0000 Subject: [PATCH 022/142] chore(deps): update dependency vite-svg-loader to v5.1.1 --- frontend/package.json | 2 +- frontend/pnpm-lock.yaml | 24 +++++++++--------------- 2 files changed, 10 insertions(+), 16 deletions(-) diff --git a/frontend/package.json b/frontend/package.json index 96363985c..e6a1d8582 100644 --- a/frontend/package.json +++ b/frontend/package.json @@ -150,7 +150,7 @@ "vite": "7.3.1", "vite-plugin-pwa": "1.2.0", "vite-plugin-vue-devtools": "8.0.7", - "vite-svg-loader": "5.1.0", + "vite-svg-loader": "5.1.1", "vitest": "4.0.18", "vue-tsc": "3.2.5", "wait-on": "9.0.4", diff --git a/frontend/pnpm-lock.yaml b/frontend/pnpm-lock.yaml index 426907c1a..4d3fcc32b 100644 --- a/frontend/pnpm-lock.yaml +++ b/frontend/pnpm-lock.yaml @@ -307,8 +307,8 @@ importers: specifier: 8.0.7 version: 8.0.7(vite@7.3.1(@types/node@24.11.0)(jiti@2.4.2)(lightningcss@1.31.1)(sass-embedded@1.97.3)(sass@1.97.3)(terser@5.31.6)(yaml@2.5.0))(vue@3.5.27(typescript@5.9.3)) vite-svg-loader: - specifier: 5.1.0 - version: 5.1.0(vue@3.5.27(typescript@5.9.3)) + specifier: 5.1.1 + version: 5.1.1(vue@3.5.27(typescript@5.9.3)) vitest: specifier: 4.0.18 version: 4.0.18(@types/node@24.11.0)(happy-dom@20.8.3)(jiti@2.4.2)(jsdom@27.4.0)(lightningcss@1.31.1)(sass-embedded@1.97.3)(sass@1.97.3)(terser@5.31.6)(yaml@2.5.0) @@ -3624,9 +3624,6 @@ packages: dompurify@3.3.1: resolution: {integrity: sha512-qkdCKzLNtrgPFP1Vo+98FRzJnBRGe4ffyCea9IwHB1fyxPOeNTHpLKYGd4Uk9xvNoH0ZoOjwZxNptyMwqrId1Q==} - domutils@3.1.0: - resolution: {integrity: sha512-H78uMmQtI2AhgDJjWeQmHwJJ2bLPD3GMmO7Zja/ZZh84wkm+4ut+IUnUdRa8uCGX88DiVx1j6FRe1XfxEgjEZA==} - domutils@3.2.2: resolution: {integrity: sha512-6kZKyUajlDuqlHKVX1w7gyslj9MPIXzIFiz/rGu35uC1wMi+kMhQwGhl4lt9unC9Vb9INnY9Z3/ZA3+FhASLaw==} @@ -6467,8 +6464,8 @@ packages: peerDependencies: vite: ^3.0.0-0 || ^4.0.0-0 || ^5.0.0-0 || ^6.0.0-0 || ^7.0.0-0 - vite-svg-loader@5.1.0: - resolution: {integrity: sha512-M/wqwtOEjgb956/+m5ZrYT/Iq6Hax0OakWbokj8+9PXOnB7b/4AxESHieEtnNEy7ZpjsjYW1/5nK8fATQMmRxw==} + vite-svg-loader@5.1.1: + resolution: {integrity: sha512-RPzcXA/EpKJA0585x58DBgs7my2VfeJ+j2j1EoHY4Zh82Y7hV4cR1fElgy2aZi85+QSrcLLoTStQ5uZjD68u+Q==} peerDependencies: vue: '>=3.2.13' @@ -10155,7 +10152,7 @@ snapshots: boolbase: 1.0.0 css-what: 6.1.0 domhandler: 5.0.3 - domutils: 3.1.0 + domutils: 3.2.2 nth-check: 2.1.1 css-tree@2.2.1: @@ -10312,12 +10309,6 @@ snapshots: optionalDependencies: '@types/trusted-types': 2.0.7 - domutils@3.1.0: - dependencies: - dom-serializer: 2.0.0 - domelementtype: 2.3.0 - domhandler: 5.0.3 - domutils@3.2.2: dependencies: dom-serializer: 2.0.0 @@ -13510,10 +13501,13 @@ snapshots: transitivePeerDependencies: - supports-color - vite-svg-loader@5.1.0(vue@3.5.27(typescript@5.9.3)): + vite-svg-loader@5.1.1(vue@3.5.27(typescript@5.9.3)): dependencies: + debug: 4.4.3 svgo: 3.3.3 vue: 3.5.27(typescript@5.9.3) + transitivePeerDependencies: + - supports-color vite@7.3.1(@types/node@24.11.0)(jiti@2.4.2)(lightningcss@1.31.1)(sass-embedded@1.97.3)(sass@1.97.3)(terser@5.31.6)(yaml@2.5.0): dependencies: From 4b5b7e69cc2642bc1b82c41c96a499bf5c4fa4ae Mon Sep 17 00:00:00 2001 From: "Frederick [Bot]" Date: Fri, 6 Mar 2026 01:17:05 +0000 Subject: [PATCH 023/142] chore(i18n): update translations via Crowdin --- frontend/src/i18n/lang/de-DE.json | 2 ++ frontend/src/i18n/lang/de-swiss.json | 2 ++ frontend/src/i18n/lang/ja-JP.json | 2 ++ 3 files changed, 6 insertions(+) diff --git a/frontend/src/i18n/lang/de-DE.json b/frontend/src/i18n/lang/de-DE.json index a4736dd34..13b3925e0 100644 --- a/frontend/src/i18n/lang/de-DE.json +++ b/frontend/src/i18n/lang/de-DE.json @@ -851,6 +851,7 @@ "doneAt": "Erledigt {0}", "updateSuccess": "Die Aufgabe wurde erfolgreich gespeichert.", "deleteSuccess": "Die Aufgabe wurde erfolgreich gelöscht.", + "duplicateSuccess": "Die Aufgabe wurde erfolgreich dupliziert.", "belongsToProject": "Diese Aufgabe gehört zum Projekt „{project}“", "back": "Zurück zum Projekt", "due": "Fällig {at}", @@ -877,6 +878,7 @@ "attachments": "Anhänge hinzufügen", "relatedTasks": "Beziehung hinzufügen", "moveProject": "Verschieben", + "duplicate": "Duplizieren", "color": "Farbe setzen", "delete": "Löschen", "favorite": "Zu Favoriten hinzufügen", diff --git a/frontend/src/i18n/lang/de-swiss.json b/frontend/src/i18n/lang/de-swiss.json index 01d306ad5..61903a34d 100644 --- a/frontend/src/i18n/lang/de-swiss.json +++ b/frontend/src/i18n/lang/de-swiss.json @@ -851,6 +851,7 @@ "doneAt": "{0} erledigt", "updateSuccess": "Die Uufgab isch erfolgriich g'speichered wore.", "deleteSuccess": "Die Uufgab isch erfolgriich g'chüblet wore.", + "duplicateSuccess": "Die Aufgabe wurde erfolgreich dupliziert.", "belongsToProject": "Diese Aufgabe gehört zum Projekt „{project}“", "back": "Zurück zum Projekt", "due": "Fällig bis {at}", @@ -877,6 +878,7 @@ "attachments": "Anhänge hinzufügen", "relatedTasks": "Beziehung hinzufügen", "moveProject": "Verschieben", + "duplicate": "Duplizieren", "color": "Farbe setzen", "delete": "Löschen", "favorite": "Zu Favoriten hinzufügen", diff --git a/frontend/src/i18n/lang/ja-JP.json b/frontend/src/i18n/lang/ja-JP.json index 0205fad8c..de46a2719 100644 --- a/frontend/src/i18n/lang/ja-JP.json +++ b/frontend/src/i18n/lang/ja-JP.json @@ -851,6 +851,7 @@ "doneAt": "完了 {0}", "updateSuccess": "タスクは正常に保存されました。", "deleteSuccess": "タスクは正常に削除されました。", + "duplicateSuccess": "タスクは正常に複製されました。", "belongsToProject": "このタスクはプロジェクト「{project}」に含まれています。", "back": "プロジェクトに戻る", "due": "期限: {at}", @@ -877,6 +878,7 @@ "attachments": "添付ファイルの追加", "relatedTasks": "関連タスクの追加", "moveProject": "移動", + "duplicate": "複製", "color": "色の設定", "delete": "削除", "favorite": "お気に入りに追加", From e5701fc0e3baa2fab48dbc72c4be5c203707a0ad Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Fri, 6 Mar 2026 01:42:43 +0000 Subject: [PATCH 024/142] chore(deps): update dev-dependencies --- desktop/package.json | 2 +- desktop/pnpm-lock.yaml | 10 +-- frontend/package.json | 2 +- frontend/pnpm-lock.yaml | 136 ++++++++++++++++++++-------------------- 4 files changed, 75 insertions(+), 75 deletions(-) diff --git a/desktop/package.json b/desktop/package.json index 3e2b4248b..7d30e11ec 100644 --- a/desktop/package.json +++ b/desktop/package.json @@ -52,7 +52,7 @@ } }, "devDependencies": { - "electron": "40.7.0", + "electron": "40.8.0", "electron-builder": "26.8.1", "unzipper": "0.12.3" }, diff --git a/desktop/pnpm-lock.yaml b/desktop/pnpm-lock.yaml index 19c58845d..a6c18b6af 100644 --- a/desktop/pnpm-lock.yaml +++ b/desktop/pnpm-lock.yaml @@ -18,8 +18,8 @@ importers: version: 5.2.1 devDependencies: electron: - specifier: 40.7.0 - version: 40.7.0 + specifier: 40.8.0 + version: 40.8.0 electron-builder: specifier: 26.8.1 version: 26.8.1(electron-builder-squirrel-windows@24.13.3) @@ -552,8 +552,8 @@ packages: electron-publish@26.8.1: resolution: {integrity: sha512-q+jrSTIh/Cv4eGZa7oVR+grEJo/FoLMYBAnSL5GCtqwUpr1T+VgKB/dn1pnzxIxqD8S/jP1yilT9VrwCqINR4w==} - electron@40.7.0: - resolution: {integrity: sha512-oQe76S/3V1rcb0+i45hAxnCH8udkRZSaHUNwglzNAEKbB94LSJ1qwbFo8+uRc2UsYZgCqSIMRcyX40GyOkD+Xw==} + electron@40.8.0: + resolution: {integrity: sha512-WoPq0Nr9Yx3g7T6VnJXdwa/rr2+VRyH3a+K+ezfMKBlf6WjxE/LmhMQabKbb6yjm9RbZhJBRcYyoLph421O2mQ==} engines: {node: '>= 12.20.55'} hasBin: true @@ -2335,7 +2335,7 @@ snapshots: transitivePeerDependencies: - supports-color - electron@40.7.0: + electron@40.8.0: dependencies: '@electron/get': 2.0.3 '@types/node': 24.10.9 diff --git a/frontend/package.json b/frontend/package.json index e6a1d8582..2dacb5cc3 100644 --- a/frontend/package.json +++ b/frontend/package.json @@ -114,7 +114,7 @@ "@tsconfig/node24": "24.0.4", "@types/codemirror": "5.60.17", "@types/is-touch-device": "1.0.3", - "@types/node": "24.11.0", + "@types/node": "24.11.2", "@types/sortablejs": "1.15.9", "@typescript-eslint/eslint-plugin": "8.56.1", "@typescript-eslint/parser": "8.56.1", diff --git a/frontend/pnpm-lock.yaml b/frontend/pnpm-lock.yaml index 4d3fcc32b..3ef6643a0 100644 --- a/frontend/pnpm-lock.yaml +++ b/frontend/pnpm-lock.yaml @@ -176,10 +176,10 @@ importers: version: 10.3.0 '@histoire/plugin-screenshot': specifier: 1.0.0-beta.1 - version: 1.0.0-beta.1(histoire@1.0.0-beta.1(@types/node@24.11.0)(lightningcss@1.31.1)(sass-embedded@1.97.3)(sass@1.97.3)(terser@5.31.6)(vite@7.3.1(@types/node@24.11.0)(jiti@2.4.2)(lightningcss@1.31.1)(sass-embedded@1.97.3)(sass@1.97.3)(terser@5.31.6)(yaml@2.5.0))(yaml@2.5.0))(typescript@5.9.3) + version: 1.0.0-beta.1(histoire@1.0.0-beta.1(@types/node@24.11.2)(lightningcss@1.31.1)(sass-embedded@1.97.3)(sass@1.97.3)(terser@5.31.6)(vite@7.3.1(@types/node@24.11.2)(jiti@2.4.2)(lightningcss@1.31.1)(sass-embedded@1.97.3)(sass@1.97.3)(terser@5.31.6)(yaml@2.5.0))(yaml@2.5.0))(typescript@5.9.3) '@histoire/plugin-vue': specifier: 1.0.0-beta.1 - version: 1.0.0-beta.1(histoire@1.0.0-beta.1(@types/node@24.11.0)(lightningcss@1.31.1)(sass-embedded@1.97.3)(sass@1.97.3)(terser@5.31.6)(vite@7.3.1(@types/node@24.11.0)(jiti@2.4.2)(lightningcss@1.31.1)(sass-embedded@1.97.3)(sass@1.97.3)(terser@5.31.6)(yaml@2.5.0))(yaml@2.5.0))(vite@7.3.1(@types/node@24.11.0)(jiti@2.4.2)(lightningcss@1.31.1)(sass-embedded@1.97.3)(sass@1.97.3)(terser@5.31.6)(yaml@2.5.0))(vue@3.5.27(typescript@5.9.3)) + version: 1.0.0-beta.1(histoire@1.0.0-beta.1(@types/node@24.11.2)(lightningcss@1.31.1)(sass-embedded@1.97.3)(sass@1.97.3)(terser@5.31.6)(vite@7.3.1(@types/node@24.11.2)(jiti@2.4.2)(lightningcss@1.31.1)(sass-embedded@1.97.3)(sass@1.97.3)(terser@5.31.6)(yaml@2.5.0))(yaml@2.5.0))(vite@7.3.1(@types/node@24.11.2)(jiti@2.4.2)(lightningcss@1.31.1)(sass-embedded@1.97.3)(sass@1.97.3)(terser@5.31.6)(yaml@2.5.0))(vue@3.5.27(typescript@5.9.3)) '@playwright/test': specifier: 1.58.2 version: 1.58.2 @@ -188,7 +188,7 @@ importers: version: 3.6.1 '@tailwindcss/vite': specifier: 4.2.1 - version: 4.2.1(vite@7.3.1(@types/node@24.11.0)(jiti@2.4.2)(lightningcss@1.31.1)(sass-embedded@1.97.3)(sass@1.97.3)(terser@5.31.6)(yaml@2.5.0)) + version: 4.2.1(vite@7.3.1(@types/node@24.11.2)(jiti@2.4.2)(lightningcss@1.31.1)(sass-embedded@1.97.3)(sass@1.97.3)(terser@5.31.6)(yaml@2.5.0)) '@tsconfig/node24': specifier: 24.0.4 version: 24.0.4 @@ -199,8 +199,8 @@ importers: specifier: 1.0.3 version: 1.0.3 '@types/node': - specifier: 24.11.0 - version: 24.11.0 + specifier: 24.11.2 + version: 24.11.2 '@types/sortablejs': specifier: 1.15.9 version: 1.15.9 @@ -212,7 +212,7 @@ importers: version: 8.56.1(eslint@9.39.3(jiti@2.4.2))(typescript@5.9.3) '@vitejs/plugin-vue': specifier: 6.0.4 - version: 6.0.4(vite@7.3.1(@types/node@24.11.0)(jiti@2.4.2)(lightningcss@1.31.1)(sass-embedded@1.97.3)(sass@1.97.3)(terser@5.31.6)(yaml@2.5.0))(vue@3.5.27(typescript@5.9.3)) + version: 6.0.4(vite@7.3.1(@types/node@24.11.2)(jiti@2.4.2)(lightningcss@1.31.1)(sass-embedded@1.97.3)(sass@1.97.3)(terser@5.31.6)(yaml@2.5.0))(vue@3.5.27(typescript@5.9.3)) '@vue/eslint-config-typescript': specifier: 14.7.0 version: 14.7.0(eslint-plugin-vue@10.8.0(@typescript-eslint/parser@8.56.1(eslint@9.39.3(jiti@2.4.2))(typescript@5.9.3))(eslint@9.39.3(jiti@2.4.2))(vue-eslint-parser@10.4.0(eslint@9.39.3(jiti@2.4.2))))(eslint@9.39.3(jiti@2.4.2))(typescript@5.9.3) @@ -254,7 +254,7 @@ importers: version: 20.8.3 histoire: specifier: 1.0.0-beta.1 - version: 1.0.0-beta.1(@types/node@24.11.0)(lightningcss@1.31.1)(sass-embedded@1.97.3)(sass@1.97.3)(terser@5.31.6)(vite@7.3.1(@types/node@24.11.0)(jiti@2.4.2)(lightningcss@1.31.1)(sass-embedded@1.97.3)(sass@1.97.3)(terser@5.31.6)(yaml@2.5.0))(yaml@2.5.0) + version: 1.0.0-beta.1(@types/node@24.11.2)(lightningcss@1.31.1)(sass-embedded@1.97.3)(sass@1.97.3)(terser@5.31.6)(vite@7.3.1(@types/node@24.11.2)(jiti@2.4.2)(lightningcss@1.31.1)(sass-embedded@1.97.3)(sass@1.97.3)(terser@5.31.6)(yaml@2.5.0))(yaml@2.5.0) postcss: specifier: 8.5.8 version: 8.5.8 @@ -299,19 +299,19 @@ importers: version: 3.0.0 vite: specifier: 7.3.1 - version: 7.3.1(@types/node@24.11.0)(jiti@2.4.2)(lightningcss@1.31.1)(sass-embedded@1.97.3)(sass@1.97.3)(terser@5.31.6)(yaml@2.5.0) + version: 7.3.1(@types/node@24.11.2)(jiti@2.4.2)(lightningcss@1.31.1)(sass-embedded@1.97.3)(sass@1.97.3)(terser@5.31.6)(yaml@2.5.0) vite-plugin-pwa: specifier: 1.2.0 - version: 1.2.0(vite@7.3.1(@types/node@24.11.0)(jiti@2.4.2)(lightningcss@1.31.1)(sass-embedded@1.97.3)(sass@1.97.3)(terser@5.31.6)(yaml@2.5.0))(workbox-build@7.4.0)(workbox-window@7.4.0) + version: 1.2.0(vite@7.3.1(@types/node@24.11.2)(jiti@2.4.2)(lightningcss@1.31.1)(sass-embedded@1.97.3)(sass@1.97.3)(terser@5.31.6)(yaml@2.5.0))(workbox-build@7.4.0)(workbox-window@7.4.0) vite-plugin-vue-devtools: specifier: 8.0.7 - version: 8.0.7(vite@7.3.1(@types/node@24.11.0)(jiti@2.4.2)(lightningcss@1.31.1)(sass-embedded@1.97.3)(sass@1.97.3)(terser@5.31.6)(yaml@2.5.0))(vue@3.5.27(typescript@5.9.3)) + version: 8.0.7(vite@7.3.1(@types/node@24.11.2)(jiti@2.4.2)(lightningcss@1.31.1)(sass-embedded@1.97.3)(sass@1.97.3)(terser@5.31.6)(yaml@2.5.0))(vue@3.5.27(typescript@5.9.3)) vite-svg-loader: specifier: 5.1.1 version: 5.1.1(vue@3.5.27(typescript@5.9.3)) vitest: specifier: 4.0.18 - version: 4.0.18(@types/node@24.11.0)(happy-dom@20.8.3)(jiti@2.4.2)(jsdom@27.4.0)(lightningcss@1.31.1)(sass-embedded@1.97.3)(sass@1.97.3)(terser@5.31.6)(yaml@2.5.0) + version: 4.0.18(@types/node@24.11.2)(happy-dom@20.8.3)(jiti@2.4.2)(jsdom@27.4.0)(lightningcss@1.31.1)(sass-embedded@1.97.3)(sass@1.97.3)(terser@5.31.6)(yaml@2.5.0) vue-tsc: specifier: 3.2.5 version: 3.2.5(typescript@5.9.3) @@ -2642,8 +2642,8 @@ packages: '@types/minimist@1.2.5': resolution: {integrity: sha512-hov8bUuiLiyFPGyFPE1lwWhmzYbirOXQNNo40+y3zow8aFVTeyn3VWL0VFFfdNddA8S4Vf0Tc062rzyNr7Paag==} - '@types/node@24.11.0': - resolution: {integrity: sha512-fPxQqz4VTgPI/IQ+lj9r0h+fDR66bzoeMGHp8ASee+32OSGIkeASsoZuJixsQoVef1QJbeubcPBxKk22QVoWdw==} + '@types/node@24.11.2': + resolution: {integrity: sha512-HTsxyfkxTNxOXBsEdgIOzbMgBjDGPvkTfw0B1m09j1LFPk8u3tSL8SNBRTSc381wXXX/Wp93qPi1kQXwnWuHgA==} '@types/normalize-package-data@2.4.4': resolution: {integrity: sha512-37i+OaWTh9qeK4LSHPsyRC7NahnGotNuZvjLSgcPzblpHB3rrCJxAOgI5gCdKm7coonsaX1Of0ILiTcnZjbfxA==} @@ -8270,17 +8270,17 @@ snapshots: dependencies: '@hapi/hoek': 11.0.7 - '@histoire/app@1.0.0-beta.1(vite@7.3.1(@types/node@24.11.0)(jiti@2.4.2)(lightningcss@1.31.1)(sass-embedded@1.97.3)(sass@1.97.3)(terser@5.31.6)(yaml@2.5.0))': + '@histoire/app@1.0.0-beta.1(vite@7.3.1(@types/node@24.11.2)(jiti@2.4.2)(lightningcss@1.31.1)(sass-embedded@1.97.3)(sass@1.97.3)(terser@5.31.6)(yaml@2.5.0))': dependencies: - '@histoire/controls': 1.0.0-beta.1(vite@7.3.1(@types/node@24.11.0)(jiti@2.4.2)(lightningcss@1.31.1)(sass-embedded@1.97.3)(sass@1.97.3)(terser@5.31.6)(yaml@2.5.0)) - '@histoire/shared': 1.0.0-beta.1(vite@7.3.1(@types/node@24.11.0)(jiti@2.4.2)(lightningcss@1.31.1)(sass-embedded@1.97.3)(sass@1.97.3)(terser@5.31.6)(yaml@2.5.0)) + '@histoire/controls': 1.0.0-beta.1(vite@7.3.1(@types/node@24.11.2)(jiti@2.4.2)(lightningcss@1.31.1)(sass-embedded@1.97.3)(sass@1.97.3)(terser@5.31.6)(yaml@2.5.0)) + '@histoire/shared': 1.0.0-beta.1(vite@7.3.1(@types/node@24.11.2)(jiti@2.4.2)(lightningcss@1.31.1)(sass-embedded@1.97.3)(sass@1.97.3)(terser@5.31.6)(yaml@2.5.0)) '@histoire/vendors': 1.0.0-beta.1 fuse.js: 7.1.0 shiki: 3.2.1 transitivePeerDependencies: - vite - '@histoire/controls@1.0.0-beta.1(vite@7.3.1(@types/node@24.11.0)(jiti@2.4.2)(lightningcss@1.31.1)(sass-embedded@1.97.3)(sass@1.97.3)(terser@5.31.6)(yaml@2.5.0))': + '@histoire/controls@1.0.0-beta.1(vite@7.3.1(@types/node@24.11.2)(jiti@2.4.2)(lightningcss@1.31.1)(sass-embedded@1.97.3)(sass@1.97.3)(terser@5.31.6)(yaml@2.5.0))': dependencies: '@codemirror/commands': 6.8.1 '@codemirror/lang-json': 6.0.1 @@ -8289,17 +8289,17 @@ snapshots: '@codemirror/state': 6.5.2 '@codemirror/theme-one-dark': 6.1.2 '@codemirror/view': 6.36.5 - '@histoire/shared': 1.0.0-beta.1(vite@7.3.1(@types/node@24.11.0)(jiti@2.4.2)(lightningcss@1.31.1)(sass-embedded@1.97.3)(sass@1.97.3)(terser@5.31.6)(yaml@2.5.0)) + '@histoire/shared': 1.0.0-beta.1(vite@7.3.1(@types/node@24.11.2)(jiti@2.4.2)(lightningcss@1.31.1)(sass-embedded@1.97.3)(sass@1.97.3)(terser@5.31.6)(yaml@2.5.0)) '@histoire/vendors': 1.0.0-beta.1 transitivePeerDependencies: - vite - '@histoire/plugin-screenshot@1.0.0-beta.1(histoire@1.0.0-beta.1(@types/node@24.11.0)(lightningcss@1.31.1)(sass-embedded@1.97.3)(sass@1.97.3)(terser@5.31.6)(vite@7.3.1(@types/node@24.11.0)(jiti@2.4.2)(lightningcss@1.31.1)(sass-embedded@1.97.3)(sass@1.97.3)(terser@5.31.6)(yaml@2.5.0))(yaml@2.5.0))(typescript@5.9.3)': + '@histoire/plugin-screenshot@1.0.0-beta.1(histoire@1.0.0-beta.1(@types/node@24.11.2)(lightningcss@1.31.1)(sass-embedded@1.97.3)(sass@1.97.3)(terser@5.31.6)(vite@7.3.1(@types/node@24.11.2)(jiti@2.4.2)(lightningcss@1.31.1)(sass-embedded@1.97.3)(sass@1.97.3)(terser@5.31.6)(yaml@2.5.0))(yaml@2.5.0))(typescript@5.9.3)': dependencies: capture-website: 4.2.0(typescript@5.9.3) defu: 6.1.4 fs-extra: 11.2.0 - histoire: 1.0.0-beta.1(@types/node@24.11.0)(lightningcss@1.31.1)(sass-embedded@1.97.3)(sass@1.97.3)(terser@5.31.6)(vite@7.3.1(@types/node@24.11.0)(jiti@2.4.2)(lightningcss@1.31.1)(sass-embedded@1.97.3)(sass@1.97.3)(terser@5.31.6)(yaml@2.5.0))(yaml@2.5.0) + histoire: 1.0.0-beta.1(@types/node@24.11.2)(lightningcss@1.31.1)(sass-embedded@1.97.3)(sass@1.97.3)(terser@5.31.6)(vite@7.3.1(@types/node@24.11.2)(jiti@2.4.2)(lightningcss@1.31.1)(sass-embedded@1.97.3)(sass@1.97.3)(terser@5.31.6)(yaml@2.5.0))(yaml@2.5.0) pathe: 1.1.2 transitivePeerDependencies: - bare-buffer @@ -8308,21 +8308,21 @@ snapshots: - typescript - utf-8-validate - '@histoire/plugin-vue@1.0.0-beta.1(histoire@1.0.0-beta.1(@types/node@24.11.0)(lightningcss@1.31.1)(sass-embedded@1.97.3)(sass@1.97.3)(terser@5.31.6)(vite@7.3.1(@types/node@24.11.0)(jiti@2.4.2)(lightningcss@1.31.1)(sass-embedded@1.97.3)(sass@1.97.3)(terser@5.31.6)(yaml@2.5.0))(yaml@2.5.0))(vite@7.3.1(@types/node@24.11.0)(jiti@2.4.2)(lightningcss@1.31.1)(sass-embedded@1.97.3)(sass@1.97.3)(terser@5.31.6)(yaml@2.5.0))(vue@3.5.27(typescript@5.9.3))': + '@histoire/plugin-vue@1.0.0-beta.1(histoire@1.0.0-beta.1(@types/node@24.11.2)(lightningcss@1.31.1)(sass-embedded@1.97.3)(sass@1.97.3)(terser@5.31.6)(vite@7.3.1(@types/node@24.11.2)(jiti@2.4.2)(lightningcss@1.31.1)(sass-embedded@1.97.3)(sass@1.97.3)(terser@5.31.6)(yaml@2.5.0))(yaml@2.5.0))(vite@7.3.1(@types/node@24.11.2)(jiti@2.4.2)(lightningcss@1.31.1)(sass-embedded@1.97.3)(sass@1.97.3)(terser@5.31.6)(yaml@2.5.0))(vue@3.5.27(typescript@5.9.3))': dependencies: - '@histoire/controls': 1.0.0-beta.1(vite@7.3.1(@types/node@24.11.0)(jiti@2.4.2)(lightningcss@1.31.1)(sass-embedded@1.97.3)(sass@1.97.3)(terser@5.31.6)(yaml@2.5.0)) - '@histoire/shared': 1.0.0-beta.1(vite@7.3.1(@types/node@24.11.0)(jiti@2.4.2)(lightningcss@1.31.1)(sass-embedded@1.97.3)(sass@1.97.3)(terser@5.31.6)(yaml@2.5.0)) + '@histoire/controls': 1.0.0-beta.1(vite@7.3.1(@types/node@24.11.2)(jiti@2.4.2)(lightningcss@1.31.1)(sass-embedded@1.97.3)(sass@1.97.3)(terser@5.31.6)(yaml@2.5.0)) + '@histoire/shared': 1.0.0-beta.1(vite@7.3.1(@types/node@24.11.2)(jiti@2.4.2)(lightningcss@1.31.1)(sass-embedded@1.97.3)(sass@1.97.3)(terser@5.31.6)(yaml@2.5.0)) '@histoire/vendors': 1.0.0-beta.1 change-case: 5.4.4 globby: 14.1.0 - histoire: 1.0.0-beta.1(@types/node@24.11.0)(lightningcss@1.31.1)(sass-embedded@1.97.3)(sass@1.97.3)(terser@5.31.6)(vite@7.3.1(@types/node@24.11.0)(jiti@2.4.2)(lightningcss@1.31.1)(sass-embedded@1.97.3)(sass@1.97.3)(terser@5.31.6)(yaml@2.5.0))(yaml@2.5.0) + histoire: 1.0.0-beta.1(@types/node@24.11.2)(lightningcss@1.31.1)(sass-embedded@1.97.3)(sass@1.97.3)(terser@5.31.6)(vite@7.3.1(@types/node@24.11.2)(jiti@2.4.2)(lightningcss@1.31.1)(sass-embedded@1.97.3)(sass@1.97.3)(terser@5.31.6)(yaml@2.5.0))(yaml@2.5.0) launch-editor: 2.10.0 pathe: 1.1.2 vue: 3.5.27(typescript@5.9.3) transitivePeerDependencies: - vite - '@histoire/shared@1.0.0-beta.1(vite@7.3.1(@types/node@24.11.0)(jiti@2.4.2)(lightningcss@1.31.1)(sass-embedded@1.97.3)(sass@1.97.3)(terser@5.31.6)(yaml@2.5.0))': + '@histoire/shared@1.0.0-beta.1(vite@7.3.1(@types/node@24.11.2)(jiti@2.4.2)(lightningcss@1.31.1)(sass-embedded@1.97.3)(sass@1.97.3)(terser@5.31.6)(yaml@2.5.0))': dependencies: '@histoire/vendors': 1.0.0-beta.1 '@types/fs-extra': 11.0.4 @@ -8330,7 +8330,7 @@ snapshots: chokidar: 4.0.3 pathe: 1.1.2 picocolors: 1.1.1 - vite: 7.3.1(@types/node@24.11.0)(jiti@2.4.2)(lightningcss@1.31.1)(sass-embedded@1.97.3)(sass@1.97.3)(terser@5.31.6)(yaml@2.5.0) + vite: 7.3.1(@types/node@24.11.2)(jiti@2.4.2)(lightningcss@1.31.1)(sass-embedded@1.97.3)(sass@1.97.3)(terser@5.31.6)(yaml@2.5.0) '@histoire/vendors@1.0.0-beta.1': {} @@ -8945,12 +8945,12 @@ snapshots: '@tailwindcss/oxide-win32-arm64-msvc': 4.2.1 '@tailwindcss/oxide-win32-x64-msvc': 4.2.1 - '@tailwindcss/vite@4.2.1(vite@7.3.1(@types/node@24.11.0)(jiti@2.4.2)(lightningcss@1.31.1)(sass-embedded@1.97.3)(sass@1.97.3)(terser@5.31.6)(yaml@2.5.0))': + '@tailwindcss/vite@4.2.1(vite@7.3.1(@types/node@24.11.2)(jiti@2.4.2)(lightningcss@1.31.1)(sass-embedded@1.97.3)(sass@1.97.3)(terser@5.31.6)(yaml@2.5.0))': dependencies: '@tailwindcss/node': 4.2.1 '@tailwindcss/oxide': 4.2.1 tailwindcss: 4.2.1 - vite: 7.3.1(@types/node@24.11.0)(jiti@2.4.2)(lightningcss@1.31.1)(sass-embedded@1.97.3)(sass@1.97.3)(terser@5.31.6)(yaml@2.5.0) + vite: 7.3.1(@types/node@24.11.2)(jiti@2.4.2)(lightningcss@1.31.1)(sass-embedded@1.97.3)(sass@1.97.3)(terser@5.31.6)(yaml@2.5.0) '@tiptap/core@3.17.0(@tiptap/pm@3.17.0)': dependencies: @@ -9175,7 +9175,7 @@ snapshots: '@types/fs-extra@11.0.4': dependencies: '@types/jsonfile': 6.1.4 - '@types/node': 24.11.0 + '@types/node': 24.11.2 '@types/hast@3.0.4': dependencies: @@ -9187,7 +9187,7 @@ snapshots: '@types/jsonfile@6.1.4': dependencies: - '@types/node': 24.11.0 + '@types/node': 24.11.2 '@types/linkify-it@5.0.0': {} @@ -9204,7 +9204,7 @@ snapshots: '@types/minimist@1.2.5': {} - '@types/node@24.11.0': + '@types/node@24.11.2': dependencies: undici-types: 7.16.0 @@ -9228,11 +9228,11 @@ snapshots: '@types/ws@8.18.1': dependencies: - '@types/node': 24.11.0 + '@types/node': 24.11.2 '@types/yauzl@2.10.3': dependencies: - '@types/node': 24.11.0 + '@types/node': 24.11.2 optional: true '@typescript-eslint/eslint-plugin@8.56.0(@typescript-eslint/parser@8.56.0(eslint@9.39.3(jiti@2.4.2))(typescript@5.9.3))(eslint@9.39.3(jiti@2.4.2))(typescript@5.9.3)': @@ -9459,10 +9459,10 @@ snapshots: '@ungap/structured-clone@1.3.0': {} - '@vitejs/plugin-vue@6.0.4(vite@7.3.1(@types/node@24.11.0)(jiti@2.4.2)(lightningcss@1.31.1)(sass-embedded@1.97.3)(sass@1.97.3)(terser@5.31.6)(yaml@2.5.0))(vue@3.5.27(typescript@5.9.3))': + '@vitejs/plugin-vue@6.0.4(vite@7.3.1(@types/node@24.11.2)(jiti@2.4.2)(lightningcss@1.31.1)(sass-embedded@1.97.3)(sass@1.97.3)(terser@5.31.6)(yaml@2.5.0))(vue@3.5.27(typescript@5.9.3))': dependencies: '@rolldown/pluginutils': 1.0.0-rc.2 - vite: 7.3.1(@types/node@24.11.0)(jiti@2.4.2)(lightningcss@1.31.1)(sass-embedded@1.97.3)(sass@1.97.3)(terser@5.31.6)(yaml@2.5.0) + vite: 7.3.1(@types/node@24.11.2)(jiti@2.4.2)(lightningcss@1.31.1)(sass-embedded@1.97.3)(sass@1.97.3)(terser@5.31.6)(yaml@2.5.0) vue: 3.5.27(typescript@5.9.3) '@vitest/expect@4.0.18': @@ -9474,13 +9474,13 @@ snapshots: chai: 6.2.2 tinyrainbow: 3.0.3 - '@vitest/mocker@4.0.18(vite@7.3.1(@types/node@24.11.0)(jiti@2.4.2)(lightningcss@1.31.1)(sass-embedded@1.97.3)(sass@1.97.3)(terser@5.31.6)(yaml@2.5.0))': + '@vitest/mocker@4.0.18(vite@7.3.1(@types/node@24.11.2)(jiti@2.4.2)(lightningcss@1.31.1)(sass-embedded@1.97.3)(sass@1.97.3)(terser@5.31.6)(yaml@2.5.0))': dependencies: '@vitest/spy': 4.0.18 estree-walker: 3.0.3 magic-string: 0.30.21 optionalDependencies: - vite: 7.3.1(@types/node@24.11.0)(jiti@2.4.2)(lightningcss@1.31.1)(sass-embedded@1.97.3)(sass@1.97.3)(terser@5.31.6)(yaml@2.5.0) + vite: 7.3.1(@types/node@24.11.2)(jiti@2.4.2)(lightningcss@1.31.1)(sass-embedded@1.97.3)(sass@1.97.3)(terser@5.31.6)(yaml@2.5.0) '@vitest/pretty-format@4.0.18': dependencies: @@ -10955,7 +10955,7 @@ snapshots: happy-dom@20.8.3: dependencies: - '@types/node': 24.11.0 + '@types/node': 24.11.2 '@types/whatwg-mimetype': 3.0.2 '@types/ws': 8.18.1 entities: 7.0.1 @@ -11013,12 +11013,12 @@ snapshots: highlight.js@11.11.1: {} - histoire@1.0.0-beta.1(@types/node@24.11.0)(lightningcss@1.31.1)(sass-embedded@1.97.3)(sass@1.97.3)(terser@5.31.6)(vite@7.3.1(@types/node@24.11.0)(jiti@2.4.2)(lightningcss@1.31.1)(sass-embedded@1.97.3)(sass@1.97.3)(terser@5.31.6)(yaml@2.5.0))(yaml@2.5.0): + histoire@1.0.0-beta.1(@types/node@24.11.2)(lightningcss@1.31.1)(sass-embedded@1.97.3)(sass@1.97.3)(terser@5.31.6)(vite@7.3.1(@types/node@24.11.2)(jiti@2.4.2)(lightningcss@1.31.1)(sass-embedded@1.97.3)(sass@1.97.3)(terser@5.31.6)(yaml@2.5.0))(yaml@2.5.0): dependencies: '@akryum/tinypool': 0.3.1 - '@histoire/app': 1.0.0-beta.1(vite@7.3.1(@types/node@24.11.0)(jiti@2.4.2)(lightningcss@1.31.1)(sass-embedded@1.97.3)(sass@1.97.3)(terser@5.31.6)(yaml@2.5.0)) - '@histoire/controls': 1.0.0-beta.1(vite@7.3.1(@types/node@24.11.0)(jiti@2.4.2)(lightningcss@1.31.1)(sass-embedded@1.97.3)(sass@1.97.3)(terser@5.31.6)(yaml@2.5.0)) - '@histoire/shared': 1.0.0-beta.1(vite@7.3.1(@types/node@24.11.0)(jiti@2.4.2)(lightningcss@1.31.1)(sass-embedded@1.97.3)(sass@1.97.3)(terser@5.31.6)(yaml@2.5.0)) + '@histoire/app': 1.0.0-beta.1(vite@7.3.1(@types/node@24.11.2)(jiti@2.4.2)(lightningcss@1.31.1)(sass-embedded@1.97.3)(sass@1.97.3)(terser@5.31.6)(yaml@2.5.0)) + '@histoire/controls': 1.0.0-beta.1(vite@7.3.1(@types/node@24.11.2)(jiti@2.4.2)(lightningcss@1.31.1)(sass-embedded@1.97.3)(sass@1.97.3)(terser@5.31.6)(yaml@2.5.0)) + '@histoire/shared': 1.0.0-beta.1(vite@7.3.1(@types/node@24.11.2)(jiti@2.4.2)(lightningcss@1.31.1)(sass-embedded@1.97.3)(sass@1.97.3)(terser@5.31.6)(yaml@2.5.0)) '@histoire/vendors': 1.0.0-beta.1 '@types/markdown-it': 14.1.2 birpc: 0.2.19 @@ -11043,8 +11043,8 @@ snapshots: sade: 1.8.1 shiki: 3.2.1 sirv: 3.0.2 - vite: 7.3.1(@types/node@24.11.0)(jiti@2.4.2)(lightningcss@1.31.1)(sass-embedded@1.97.3)(sass@1.97.3)(terser@5.31.6)(yaml@2.5.0) - vite-node: 3.2.4(@types/node@24.11.0)(jiti@2.4.2)(lightningcss@1.31.1)(sass-embedded@1.97.3)(sass@1.97.3)(terser@5.31.6)(yaml@2.5.0) + vite: 7.3.1(@types/node@24.11.2)(jiti@2.4.2)(lightningcss@1.31.1)(sass-embedded@1.97.3)(sass@1.97.3)(terser@5.31.6)(yaml@2.5.0) + vite-node: 3.2.4(@types/node@24.11.2)(jiti@2.4.2)(lightningcss@1.31.1)(sass-embedded@1.97.3)(sass@1.97.3)(terser@5.31.6)(yaml@2.5.0) transitivePeerDependencies: - '@exodus/crypto' - '@types/node' @@ -13415,23 +13415,23 @@ snapshots: '@types/unist': 3.0.3 vfile-message: 4.0.2 - vite-dev-rpc@1.1.0(vite@7.3.1(@types/node@24.11.0)(jiti@2.4.2)(lightningcss@1.31.1)(sass-embedded@1.97.3)(sass@1.97.3)(terser@5.31.6)(yaml@2.5.0)): + vite-dev-rpc@1.1.0(vite@7.3.1(@types/node@24.11.2)(jiti@2.4.2)(lightningcss@1.31.1)(sass-embedded@1.97.3)(sass@1.97.3)(terser@5.31.6)(yaml@2.5.0)): dependencies: birpc: 2.6.1 - vite: 7.3.1(@types/node@24.11.0)(jiti@2.4.2)(lightningcss@1.31.1)(sass-embedded@1.97.3)(sass@1.97.3)(terser@5.31.6)(yaml@2.5.0) - vite-hot-client: 2.1.0(vite@7.3.1(@types/node@24.11.0)(jiti@2.4.2)(lightningcss@1.31.1)(sass-embedded@1.97.3)(sass@1.97.3)(terser@5.31.6)(yaml@2.5.0)) + vite: 7.3.1(@types/node@24.11.2)(jiti@2.4.2)(lightningcss@1.31.1)(sass-embedded@1.97.3)(sass@1.97.3)(terser@5.31.6)(yaml@2.5.0) + vite-hot-client: 2.1.0(vite@7.3.1(@types/node@24.11.2)(jiti@2.4.2)(lightningcss@1.31.1)(sass-embedded@1.97.3)(sass@1.97.3)(terser@5.31.6)(yaml@2.5.0)) - vite-hot-client@2.1.0(vite@7.3.1(@types/node@24.11.0)(jiti@2.4.2)(lightningcss@1.31.1)(sass-embedded@1.97.3)(sass@1.97.3)(terser@5.31.6)(yaml@2.5.0)): + vite-hot-client@2.1.0(vite@7.3.1(@types/node@24.11.2)(jiti@2.4.2)(lightningcss@1.31.1)(sass-embedded@1.97.3)(sass@1.97.3)(terser@5.31.6)(yaml@2.5.0)): dependencies: - vite: 7.3.1(@types/node@24.11.0)(jiti@2.4.2)(lightningcss@1.31.1)(sass-embedded@1.97.3)(sass@1.97.3)(terser@5.31.6)(yaml@2.5.0) + vite: 7.3.1(@types/node@24.11.2)(jiti@2.4.2)(lightningcss@1.31.1)(sass-embedded@1.97.3)(sass@1.97.3)(terser@5.31.6)(yaml@2.5.0) - vite-node@3.2.4(@types/node@24.11.0)(jiti@2.4.2)(lightningcss@1.31.1)(sass-embedded@1.97.3)(sass@1.97.3)(terser@5.31.6)(yaml@2.5.0): + vite-node@3.2.4(@types/node@24.11.2)(jiti@2.4.2)(lightningcss@1.31.1)(sass-embedded@1.97.3)(sass@1.97.3)(terser@5.31.6)(yaml@2.5.0): dependencies: cac: 6.7.14 debug: 4.4.3 es-module-lexer: 1.7.0 pathe: 2.0.3 - vite: 7.3.1(@types/node@24.11.0)(jiti@2.4.2)(lightningcss@1.31.1)(sass-embedded@1.97.3)(sass@1.97.3)(terser@5.31.6)(yaml@2.5.0) + vite: 7.3.1(@types/node@24.11.2)(jiti@2.4.2)(lightningcss@1.31.1)(sass-embedded@1.97.3)(sass@1.97.3)(terser@5.31.6)(yaml@2.5.0) transitivePeerDependencies: - '@types/node' - jiti @@ -13446,7 +13446,7 @@ snapshots: - tsx - yaml - vite-plugin-inspect@11.3.3(vite@7.3.1(@types/node@24.11.0)(jiti@2.4.2)(lightningcss@1.31.1)(sass-embedded@1.97.3)(sass@1.97.3)(terser@5.31.6)(yaml@2.5.0)): + vite-plugin-inspect@11.3.3(vite@7.3.1(@types/node@24.11.2)(jiti@2.4.2)(lightningcss@1.31.1)(sass-embedded@1.97.3)(sass@1.97.3)(terser@5.31.6)(yaml@2.5.0)): dependencies: ansis: 4.1.0 debug: 4.4.3 @@ -13456,37 +13456,37 @@ snapshots: perfect-debounce: 2.0.0 sirv: 3.0.2 unplugin-utils: 0.3.0 - vite: 7.3.1(@types/node@24.11.0)(jiti@2.4.2)(lightningcss@1.31.1)(sass-embedded@1.97.3)(sass@1.97.3)(terser@5.31.6)(yaml@2.5.0) - vite-dev-rpc: 1.1.0(vite@7.3.1(@types/node@24.11.0)(jiti@2.4.2)(lightningcss@1.31.1)(sass-embedded@1.97.3)(sass@1.97.3)(terser@5.31.6)(yaml@2.5.0)) + vite: 7.3.1(@types/node@24.11.2)(jiti@2.4.2)(lightningcss@1.31.1)(sass-embedded@1.97.3)(sass@1.97.3)(terser@5.31.6)(yaml@2.5.0) + vite-dev-rpc: 1.1.0(vite@7.3.1(@types/node@24.11.2)(jiti@2.4.2)(lightningcss@1.31.1)(sass-embedded@1.97.3)(sass@1.97.3)(terser@5.31.6)(yaml@2.5.0)) transitivePeerDependencies: - supports-color - vite-plugin-pwa@1.2.0(vite@7.3.1(@types/node@24.11.0)(jiti@2.4.2)(lightningcss@1.31.1)(sass-embedded@1.97.3)(sass@1.97.3)(terser@5.31.6)(yaml@2.5.0))(workbox-build@7.4.0)(workbox-window@7.4.0): + vite-plugin-pwa@1.2.0(vite@7.3.1(@types/node@24.11.2)(jiti@2.4.2)(lightningcss@1.31.1)(sass-embedded@1.97.3)(sass@1.97.3)(terser@5.31.6)(yaml@2.5.0))(workbox-build@7.4.0)(workbox-window@7.4.0): dependencies: debug: 4.4.3 pretty-bytes: 6.1.1 tinyglobby: 0.2.15 - vite: 7.3.1(@types/node@24.11.0)(jiti@2.4.2)(lightningcss@1.31.1)(sass-embedded@1.97.3)(sass@1.97.3)(terser@5.31.6)(yaml@2.5.0) + vite: 7.3.1(@types/node@24.11.2)(jiti@2.4.2)(lightningcss@1.31.1)(sass-embedded@1.97.3)(sass@1.97.3)(terser@5.31.6)(yaml@2.5.0) workbox-build: 7.4.0 workbox-window: 7.4.0 transitivePeerDependencies: - supports-color - vite-plugin-vue-devtools@8.0.7(vite@7.3.1(@types/node@24.11.0)(jiti@2.4.2)(lightningcss@1.31.1)(sass-embedded@1.97.3)(sass@1.97.3)(terser@5.31.6)(yaml@2.5.0))(vue@3.5.27(typescript@5.9.3)): + vite-plugin-vue-devtools@8.0.7(vite@7.3.1(@types/node@24.11.2)(jiti@2.4.2)(lightningcss@1.31.1)(sass-embedded@1.97.3)(sass@1.97.3)(terser@5.31.6)(yaml@2.5.0))(vue@3.5.27(typescript@5.9.3)): dependencies: '@vue/devtools-core': 8.0.7(vue@3.5.27(typescript@5.9.3)) '@vue/devtools-kit': 8.0.7 '@vue/devtools-shared': 8.0.7 sirv: 3.0.2 - vite: 7.3.1(@types/node@24.11.0)(jiti@2.4.2)(lightningcss@1.31.1)(sass-embedded@1.97.3)(sass@1.97.3)(terser@5.31.6)(yaml@2.5.0) - vite-plugin-inspect: 11.3.3(vite@7.3.1(@types/node@24.11.0)(jiti@2.4.2)(lightningcss@1.31.1)(sass-embedded@1.97.3)(sass@1.97.3)(terser@5.31.6)(yaml@2.5.0)) - vite-plugin-vue-inspector: 5.3.2(vite@7.3.1(@types/node@24.11.0)(jiti@2.4.2)(lightningcss@1.31.1)(sass-embedded@1.97.3)(sass@1.97.3)(terser@5.31.6)(yaml@2.5.0)) + vite: 7.3.1(@types/node@24.11.2)(jiti@2.4.2)(lightningcss@1.31.1)(sass-embedded@1.97.3)(sass@1.97.3)(terser@5.31.6)(yaml@2.5.0) + vite-plugin-inspect: 11.3.3(vite@7.3.1(@types/node@24.11.2)(jiti@2.4.2)(lightningcss@1.31.1)(sass-embedded@1.97.3)(sass@1.97.3)(terser@5.31.6)(yaml@2.5.0)) + vite-plugin-vue-inspector: 5.3.2(vite@7.3.1(@types/node@24.11.2)(jiti@2.4.2)(lightningcss@1.31.1)(sass-embedded@1.97.3)(sass@1.97.3)(terser@5.31.6)(yaml@2.5.0)) transitivePeerDependencies: - '@nuxt/kit' - supports-color - vue - vite-plugin-vue-inspector@5.3.2(vite@7.3.1(@types/node@24.11.0)(jiti@2.4.2)(lightningcss@1.31.1)(sass-embedded@1.97.3)(sass@1.97.3)(terser@5.31.6)(yaml@2.5.0)): + vite-plugin-vue-inspector@5.3.2(vite@7.3.1(@types/node@24.11.2)(jiti@2.4.2)(lightningcss@1.31.1)(sass-embedded@1.97.3)(sass@1.97.3)(terser@5.31.6)(yaml@2.5.0)): dependencies: '@babel/core': 7.26.0 '@babel/plugin-proposal-decorators': 7.25.9(@babel/core@7.26.0) @@ -13497,7 +13497,7 @@ snapshots: '@vue/compiler-dom': 3.5.27 kolorist: 1.8.0 magic-string: 0.30.21 - vite: 7.3.1(@types/node@24.11.0)(jiti@2.4.2)(lightningcss@1.31.1)(sass-embedded@1.97.3)(sass@1.97.3)(terser@5.31.6)(yaml@2.5.0) + vite: 7.3.1(@types/node@24.11.2)(jiti@2.4.2)(lightningcss@1.31.1)(sass-embedded@1.97.3)(sass@1.97.3)(terser@5.31.6)(yaml@2.5.0) transitivePeerDependencies: - supports-color @@ -13509,7 +13509,7 @@ snapshots: transitivePeerDependencies: - supports-color - vite@7.3.1(@types/node@24.11.0)(jiti@2.4.2)(lightningcss@1.31.1)(sass-embedded@1.97.3)(sass@1.97.3)(terser@5.31.6)(yaml@2.5.0): + vite@7.3.1(@types/node@24.11.2)(jiti@2.4.2)(lightningcss@1.31.1)(sass-embedded@1.97.3)(sass@1.97.3)(terser@5.31.6)(yaml@2.5.0): dependencies: esbuild: 0.27.3 fdir: 6.5.0(picomatch@4.0.3) @@ -13518,7 +13518,7 @@ snapshots: rollup: 4.59.0 tinyglobby: 0.2.15 optionalDependencies: - '@types/node': 24.11.0 + '@types/node': 24.11.2 fsevents: 2.3.3 jiti: 2.4.2 lightningcss: 1.31.1 @@ -13527,10 +13527,10 @@ snapshots: terser: 5.31.6 yaml: 2.5.0 - vitest@4.0.18(@types/node@24.11.0)(happy-dom@20.8.3)(jiti@2.4.2)(jsdom@27.4.0)(lightningcss@1.31.1)(sass-embedded@1.97.3)(sass@1.97.3)(terser@5.31.6)(yaml@2.5.0): + vitest@4.0.18(@types/node@24.11.2)(happy-dom@20.8.3)(jiti@2.4.2)(jsdom@27.4.0)(lightningcss@1.31.1)(sass-embedded@1.97.3)(sass@1.97.3)(terser@5.31.6)(yaml@2.5.0): dependencies: '@vitest/expect': 4.0.18 - '@vitest/mocker': 4.0.18(vite@7.3.1(@types/node@24.11.0)(jiti@2.4.2)(lightningcss@1.31.1)(sass-embedded@1.97.3)(sass@1.97.3)(terser@5.31.6)(yaml@2.5.0)) + '@vitest/mocker': 4.0.18(vite@7.3.1(@types/node@24.11.2)(jiti@2.4.2)(lightningcss@1.31.1)(sass-embedded@1.97.3)(sass@1.97.3)(terser@5.31.6)(yaml@2.5.0)) '@vitest/pretty-format': 4.0.18 '@vitest/runner': 4.0.18 '@vitest/snapshot': 4.0.18 @@ -13547,10 +13547,10 @@ snapshots: tinyexec: 1.0.2 tinyglobby: 0.2.15 tinyrainbow: 3.0.3 - vite: 7.3.1(@types/node@24.11.0)(jiti@2.4.2)(lightningcss@1.31.1)(sass-embedded@1.97.3)(sass@1.97.3)(terser@5.31.6)(yaml@2.5.0) + vite: 7.3.1(@types/node@24.11.2)(jiti@2.4.2)(lightningcss@1.31.1)(sass-embedded@1.97.3)(sass@1.97.3)(terser@5.31.6)(yaml@2.5.0) why-is-node-running: 2.3.0 optionalDependencies: - '@types/node': 24.11.0 + '@types/node': 24.11.2 happy-dom: 20.8.3 jsdom: 27.4.0 transitivePeerDependencies: From b85ad9c298239591cd5f641d386a6f552ddd1249 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Fri, 6 Mar 2026 07:49:16 +0000 Subject: [PATCH 025/142] chore(deps): bump dompurify from 3.3.1 to 3.3.2 in /frontend Bumps [dompurify](https://github.com/cure53/DOMPurify) from 3.3.1 to 3.3.2. - [Release notes](https://github.com/cure53/DOMPurify/releases) - [Commits](https://github.com/cure53/DOMPurify/compare/3.3.1...3.3.2) --- updated-dependencies: - dependency-name: dompurify dependency-version: 3.3.2 dependency-type: direct:production ... Signed-off-by: dependabot[bot] --- frontend/package.json | 2 +- frontend/pnpm-lock.yaml | 11 ++++++----- 2 files changed, 7 insertions(+), 6 deletions(-) diff --git a/frontend/package.json b/frontend/package.json index 2dacb5cc3..35931b461 100644 --- a/frontend/package.json +++ b/frontend/package.json @@ -81,7 +81,7 @@ "bulma-css-variables": "0.9.33", "change-case": "5.4.4", "dayjs": "1.11.19", - "dompurify": "3.3.1", + "dompurify": "3.3.2", "fast-deep-equal": "3.1.3", "flatpickr": "4.6.13", "flexsearch": "0.8.212", diff --git a/frontend/pnpm-lock.yaml b/frontend/pnpm-lock.yaml index 3ef6643a0..d1061d4d5 100644 --- a/frontend/pnpm-lock.yaml +++ b/frontend/pnpm-lock.yaml @@ -105,8 +105,8 @@ importers: specifier: 1.11.19 version: 1.11.19 dompurify: - specifier: 3.3.1 - version: 3.3.1 + specifier: 3.3.2 + version: 3.3.2 fast-deep-equal: specifier: 3.1.3 version: 3.1.3 @@ -3621,8 +3621,9 @@ packages: resolution: {integrity: sha512-cgwlv/1iFQiFnU96XXgROh8xTeetsnJiDsTc7TYCLFd9+/WNkIqPTxiM/8pSd8VIrhXGTf1Ny1q1hquVqDJB5w==} engines: {node: '>= 4'} - dompurify@3.3.1: - resolution: {integrity: sha512-qkdCKzLNtrgPFP1Vo+98FRzJnBRGe4ffyCea9IwHB1fyxPOeNTHpLKYGd4Uk9xvNoH0ZoOjwZxNptyMwqrId1Q==} + dompurify@3.3.2: + resolution: {integrity: sha512-6obghkliLdmKa56xdbLOpUZ43pAR6xFy1uOrxBaIDjT+yaRuuybLjGS9eVBoSR/UPU5fq3OXClEHLJNGvbxKpQ==} + engines: {node: '>=20'} domutils@3.2.2: resolution: {integrity: sha512-6kZKyUajlDuqlHKVX1w7gyslj9MPIXzIFiz/rGu35uC1wMi+kMhQwGhl4lt9unC9Vb9INnY9Z3/ZA3+FhASLaw==} @@ -10305,7 +10306,7 @@ snapshots: dependencies: domelementtype: 2.3.0 - dompurify@3.3.1: + dompurify@3.3.2: optionalDependencies: '@types/trusted-types': 2.0.7 From c49d8e129a9069acfe4d07e637c6ee1be76b10e8 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Fri, 6 Mar 2026 07:49:06 +0000 Subject: [PATCH 026/142] chore(deps): update dev-dependencies --- frontend/package.json | 4 +- frontend/pnpm-lock.yaml | 150 ++++++++++++++++++++-------------------- 2 files changed, 77 insertions(+), 77 deletions(-) diff --git a/frontend/package.json b/frontend/package.json index 35931b461..0147eda44 100644 --- a/frontend/package.json +++ b/frontend/package.json @@ -114,7 +114,7 @@ "@tsconfig/node24": "24.0.4", "@types/codemirror": "5.60.17", "@types/is-touch-device": "1.0.3", - "@types/node": "24.11.2", + "@types/node": "24.12.0", "@types/sortablejs": "1.15.9", "@typescript-eslint/eslint-plugin": "8.56.1", "@typescript-eslint/parser": "8.56.1", @@ -125,7 +125,7 @@ "@vueuse/shared": "14.2.1", "autoprefixer": "10.4.27", "browserslist": "4.28.1", - "caniuse-lite": "1.0.30001776", + "caniuse-lite": "1.0.30001777", "csstype": "3.2.3", "esbuild": "0.27.3", "eslint": "9.39.3", diff --git a/frontend/pnpm-lock.yaml b/frontend/pnpm-lock.yaml index d1061d4d5..c5a7ec2db 100644 --- a/frontend/pnpm-lock.yaml +++ b/frontend/pnpm-lock.yaml @@ -176,10 +176,10 @@ importers: version: 10.3.0 '@histoire/plugin-screenshot': specifier: 1.0.0-beta.1 - version: 1.0.0-beta.1(histoire@1.0.0-beta.1(@types/node@24.11.2)(lightningcss@1.31.1)(sass-embedded@1.97.3)(sass@1.97.3)(terser@5.31.6)(vite@7.3.1(@types/node@24.11.2)(jiti@2.4.2)(lightningcss@1.31.1)(sass-embedded@1.97.3)(sass@1.97.3)(terser@5.31.6)(yaml@2.5.0))(yaml@2.5.0))(typescript@5.9.3) + version: 1.0.0-beta.1(histoire@1.0.0-beta.1(@types/node@24.12.0)(lightningcss@1.31.1)(sass-embedded@1.97.3)(sass@1.97.3)(terser@5.31.6)(vite@7.3.1(@types/node@24.12.0)(jiti@2.4.2)(lightningcss@1.31.1)(sass-embedded@1.97.3)(sass@1.97.3)(terser@5.31.6)(yaml@2.5.0))(yaml@2.5.0))(typescript@5.9.3) '@histoire/plugin-vue': specifier: 1.0.0-beta.1 - version: 1.0.0-beta.1(histoire@1.0.0-beta.1(@types/node@24.11.2)(lightningcss@1.31.1)(sass-embedded@1.97.3)(sass@1.97.3)(terser@5.31.6)(vite@7.3.1(@types/node@24.11.2)(jiti@2.4.2)(lightningcss@1.31.1)(sass-embedded@1.97.3)(sass@1.97.3)(terser@5.31.6)(yaml@2.5.0))(yaml@2.5.0))(vite@7.3.1(@types/node@24.11.2)(jiti@2.4.2)(lightningcss@1.31.1)(sass-embedded@1.97.3)(sass@1.97.3)(terser@5.31.6)(yaml@2.5.0))(vue@3.5.27(typescript@5.9.3)) + version: 1.0.0-beta.1(histoire@1.0.0-beta.1(@types/node@24.12.0)(lightningcss@1.31.1)(sass-embedded@1.97.3)(sass@1.97.3)(terser@5.31.6)(vite@7.3.1(@types/node@24.12.0)(jiti@2.4.2)(lightningcss@1.31.1)(sass-embedded@1.97.3)(sass@1.97.3)(terser@5.31.6)(yaml@2.5.0))(yaml@2.5.0))(vite@7.3.1(@types/node@24.12.0)(jiti@2.4.2)(lightningcss@1.31.1)(sass-embedded@1.97.3)(sass@1.97.3)(terser@5.31.6)(yaml@2.5.0))(vue@3.5.27(typescript@5.9.3)) '@playwright/test': specifier: 1.58.2 version: 1.58.2 @@ -188,7 +188,7 @@ importers: version: 3.6.1 '@tailwindcss/vite': specifier: 4.2.1 - version: 4.2.1(vite@7.3.1(@types/node@24.11.2)(jiti@2.4.2)(lightningcss@1.31.1)(sass-embedded@1.97.3)(sass@1.97.3)(terser@5.31.6)(yaml@2.5.0)) + version: 4.2.1(vite@7.3.1(@types/node@24.12.0)(jiti@2.4.2)(lightningcss@1.31.1)(sass-embedded@1.97.3)(sass@1.97.3)(terser@5.31.6)(yaml@2.5.0)) '@tsconfig/node24': specifier: 24.0.4 version: 24.0.4 @@ -199,8 +199,8 @@ importers: specifier: 1.0.3 version: 1.0.3 '@types/node': - specifier: 24.11.2 - version: 24.11.2 + specifier: 24.12.0 + version: 24.12.0 '@types/sortablejs': specifier: 1.15.9 version: 1.15.9 @@ -212,7 +212,7 @@ importers: version: 8.56.1(eslint@9.39.3(jiti@2.4.2))(typescript@5.9.3) '@vitejs/plugin-vue': specifier: 6.0.4 - version: 6.0.4(vite@7.3.1(@types/node@24.11.2)(jiti@2.4.2)(lightningcss@1.31.1)(sass-embedded@1.97.3)(sass@1.97.3)(terser@5.31.6)(yaml@2.5.0))(vue@3.5.27(typescript@5.9.3)) + version: 6.0.4(vite@7.3.1(@types/node@24.12.0)(jiti@2.4.2)(lightningcss@1.31.1)(sass-embedded@1.97.3)(sass@1.97.3)(terser@5.31.6)(yaml@2.5.0))(vue@3.5.27(typescript@5.9.3)) '@vue/eslint-config-typescript': specifier: 14.7.0 version: 14.7.0(eslint-plugin-vue@10.8.0(@typescript-eslint/parser@8.56.1(eslint@9.39.3(jiti@2.4.2))(typescript@5.9.3))(eslint@9.39.3(jiti@2.4.2))(vue-eslint-parser@10.4.0(eslint@9.39.3(jiti@2.4.2))))(eslint@9.39.3(jiti@2.4.2))(typescript@5.9.3) @@ -232,8 +232,8 @@ importers: specifier: 4.28.1 version: 4.28.1 caniuse-lite: - specifier: 1.0.30001776 - version: 1.0.30001776 + specifier: 1.0.30001777 + version: 1.0.30001777 csstype: specifier: 3.2.3 version: 3.2.3 @@ -254,7 +254,7 @@ importers: version: 20.8.3 histoire: specifier: 1.0.0-beta.1 - version: 1.0.0-beta.1(@types/node@24.11.2)(lightningcss@1.31.1)(sass-embedded@1.97.3)(sass@1.97.3)(terser@5.31.6)(vite@7.3.1(@types/node@24.11.2)(jiti@2.4.2)(lightningcss@1.31.1)(sass-embedded@1.97.3)(sass@1.97.3)(terser@5.31.6)(yaml@2.5.0))(yaml@2.5.0) + version: 1.0.0-beta.1(@types/node@24.12.0)(lightningcss@1.31.1)(sass-embedded@1.97.3)(sass@1.97.3)(terser@5.31.6)(vite@7.3.1(@types/node@24.12.0)(jiti@2.4.2)(lightningcss@1.31.1)(sass-embedded@1.97.3)(sass@1.97.3)(terser@5.31.6)(yaml@2.5.0))(yaml@2.5.0) postcss: specifier: 8.5.8 version: 8.5.8 @@ -299,19 +299,19 @@ importers: version: 3.0.0 vite: specifier: 7.3.1 - version: 7.3.1(@types/node@24.11.2)(jiti@2.4.2)(lightningcss@1.31.1)(sass-embedded@1.97.3)(sass@1.97.3)(terser@5.31.6)(yaml@2.5.0) + version: 7.3.1(@types/node@24.12.0)(jiti@2.4.2)(lightningcss@1.31.1)(sass-embedded@1.97.3)(sass@1.97.3)(terser@5.31.6)(yaml@2.5.0) vite-plugin-pwa: specifier: 1.2.0 - version: 1.2.0(vite@7.3.1(@types/node@24.11.2)(jiti@2.4.2)(lightningcss@1.31.1)(sass-embedded@1.97.3)(sass@1.97.3)(terser@5.31.6)(yaml@2.5.0))(workbox-build@7.4.0)(workbox-window@7.4.0) + version: 1.2.0(vite@7.3.1(@types/node@24.12.0)(jiti@2.4.2)(lightningcss@1.31.1)(sass-embedded@1.97.3)(sass@1.97.3)(terser@5.31.6)(yaml@2.5.0))(workbox-build@7.4.0)(workbox-window@7.4.0) vite-plugin-vue-devtools: specifier: 8.0.7 - version: 8.0.7(vite@7.3.1(@types/node@24.11.2)(jiti@2.4.2)(lightningcss@1.31.1)(sass-embedded@1.97.3)(sass@1.97.3)(terser@5.31.6)(yaml@2.5.0))(vue@3.5.27(typescript@5.9.3)) + version: 8.0.7(vite@7.3.1(@types/node@24.12.0)(jiti@2.4.2)(lightningcss@1.31.1)(sass-embedded@1.97.3)(sass@1.97.3)(terser@5.31.6)(yaml@2.5.0))(vue@3.5.27(typescript@5.9.3)) vite-svg-loader: specifier: 5.1.1 version: 5.1.1(vue@3.5.27(typescript@5.9.3)) vitest: specifier: 4.0.18 - version: 4.0.18(@types/node@24.11.2)(happy-dom@20.8.3)(jiti@2.4.2)(jsdom@27.4.0)(lightningcss@1.31.1)(sass-embedded@1.97.3)(sass@1.97.3)(terser@5.31.6)(yaml@2.5.0) + version: 4.0.18(@types/node@24.12.0)(happy-dom@20.8.3)(jiti@2.4.2)(jsdom@27.4.0)(lightningcss@1.31.1)(sass-embedded@1.97.3)(sass@1.97.3)(terser@5.31.6)(yaml@2.5.0) vue-tsc: specifier: 3.2.5 version: 3.2.5(typescript@5.9.3) @@ -2642,8 +2642,8 @@ packages: '@types/minimist@1.2.5': resolution: {integrity: sha512-hov8bUuiLiyFPGyFPE1lwWhmzYbirOXQNNo40+y3zow8aFVTeyn3VWL0VFFfdNddA8S4Vf0Tc062rzyNr7Paag==} - '@types/node@24.11.2': - resolution: {integrity: sha512-HTsxyfkxTNxOXBsEdgIOzbMgBjDGPvkTfw0B1m09j1LFPk8u3tSL8SNBRTSc381wXXX/Wp93qPi1kQXwnWuHgA==} + '@types/node@24.12.0': + resolution: {integrity: sha512-GYDxsZi3ChgmckRT9HPU0WEhKLP08ev/Yfcq2AstjrDASOYCSXeyjDsHg4v5t4jOj7cyDX3vmprafKlWIG9MXQ==} '@types/normalize-package-data@2.4.4': resolution: {integrity: sha512-37i+OaWTh9qeK4LSHPsyRC7NahnGotNuZvjLSgcPzblpHB3rrCJxAOgI5gCdKm7coonsaX1Of0ILiTcnZjbfxA==} @@ -3270,8 +3270,8 @@ packages: resolution: {integrity: sha512-8WB3Jcas3swSvjIeA2yvCJ+Miyz5l1ZmB6HFb9R1317dt9LCQoswg/BGrmAmkWVEszSrrg4RwmO46qIm2OEnSA==} engines: {node: '>=16'} - caniuse-lite@1.0.30001776: - resolution: {integrity: sha512-sg01JDPzZ9jGshqKSckOQthXnYwOEP50jeVFhaSFbZcOy05TiuuaffDOfcwtCisJ9kNQuLBFibYywv2Bgm9osw==} + caniuse-lite@1.0.30001777: + resolution: {integrity: sha512-tmN+fJxroPndC74efCdp12j+0rk0RHwV5Jwa1zWaFVyw2ZxAuPeG8ZgWC3Wz7uSjT3qMRQ5XHZ4COgQmsCMJAQ==} capture-website@4.2.0: resolution: {integrity: sha512-EmkSn36CXTC8tUsS6aNmvvsdpfVTYYkuRp7U5bV9gcJwcDbqqA5c0Op/iskYPKtDdOkuVp61mjn/LLywX0h7cw==} @@ -8271,17 +8271,17 @@ snapshots: dependencies: '@hapi/hoek': 11.0.7 - '@histoire/app@1.0.0-beta.1(vite@7.3.1(@types/node@24.11.2)(jiti@2.4.2)(lightningcss@1.31.1)(sass-embedded@1.97.3)(sass@1.97.3)(terser@5.31.6)(yaml@2.5.0))': + '@histoire/app@1.0.0-beta.1(vite@7.3.1(@types/node@24.12.0)(jiti@2.4.2)(lightningcss@1.31.1)(sass-embedded@1.97.3)(sass@1.97.3)(terser@5.31.6)(yaml@2.5.0))': dependencies: - '@histoire/controls': 1.0.0-beta.1(vite@7.3.1(@types/node@24.11.2)(jiti@2.4.2)(lightningcss@1.31.1)(sass-embedded@1.97.3)(sass@1.97.3)(terser@5.31.6)(yaml@2.5.0)) - '@histoire/shared': 1.0.0-beta.1(vite@7.3.1(@types/node@24.11.2)(jiti@2.4.2)(lightningcss@1.31.1)(sass-embedded@1.97.3)(sass@1.97.3)(terser@5.31.6)(yaml@2.5.0)) + '@histoire/controls': 1.0.0-beta.1(vite@7.3.1(@types/node@24.12.0)(jiti@2.4.2)(lightningcss@1.31.1)(sass-embedded@1.97.3)(sass@1.97.3)(terser@5.31.6)(yaml@2.5.0)) + '@histoire/shared': 1.0.0-beta.1(vite@7.3.1(@types/node@24.12.0)(jiti@2.4.2)(lightningcss@1.31.1)(sass-embedded@1.97.3)(sass@1.97.3)(terser@5.31.6)(yaml@2.5.0)) '@histoire/vendors': 1.0.0-beta.1 fuse.js: 7.1.0 shiki: 3.2.1 transitivePeerDependencies: - vite - '@histoire/controls@1.0.0-beta.1(vite@7.3.1(@types/node@24.11.2)(jiti@2.4.2)(lightningcss@1.31.1)(sass-embedded@1.97.3)(sass@1.97.3)(terser@5.31.6)(yaml@2.5.0))': + '@histoire/controls@1.0.0-beta.1(vite@7.3.1(@types/node@24.12.0)(jiti@2.4.2)(lightningcss@1.31.1)(sass-embedded@1.97.3)(sass@1.97.3)(terser@5.31.6)(yaml@2.5.0))': dependencies: '@codemirror/commands': 6.8.1 '@codemirror/lang-json': 6.0.1 @@ -8290,17 +8290,17 @@ snapshots: '@codemirror/state': 6.5.2 '@codemirror/theme-one-dark': 6.1.2 '@codemirror/view': 6.36.5 - '@histoire/shared': 1.0.0-beta.1(vite@7.3.1(@types/node@24.11.2)(jiti@2.4.2)(lightningcss@1.31.1)(sass-embedded@1.97.3)(sass@1.97.3)(terser@5.31.6)(yaml@2.5.0)) + '@histoire/shared': 1.0.0-beta.1(vite@7.3.1(@types/node@24.12.0)(jiti@2.4.2)(lightningcss@1.31.1)(sass-embedded@1.97.3)(sass@1.97.3)(terser@5.31.6)(yaml@2.5.0)) '@histoire/vendors': 1.0.0-beta.1 transitivePeerDependencies: - vite - '@histoire/plugin-screenshot@1.0.0-beta.1(histoire@1.0.0-beta.1(@types/node@24.11.2)(lightningcss@1.31.1)(sass-embedded@1.97.3)(sass@1.97.3)(terser@5.31.6)(vite@7.3.1(@types/node@24.11.2)(jiti@2.4.2)(lightningcss@1.31.1)(sass-embedded@1.97.3)(sass@1.97.3)(terser@5.31.6)(yaml@2.5.0))(yaml@2.5.0))(typescript@5.9.3)': + '@histoire/plugin-screenshot@1.0.0-beta.1(histoire@1.0.0-beta.1(@types/node@24.12.0)(lightningcss@1.31.1)(sass-embedded@1.97.3)(sass@1.97.3)(terser@5.31.6)(vite@7.3.1(@types/node@24.12.0)(jiti@2.4.2)(lightningcss@1.31.1)(sass-embedded@1.97.3)(sass@1.97.3)(terser@5.31.6)(yaml@2.5.0))(yaml@2.5.0))(typescript@5.9.3)': dependencies: capture-website: 4.2.0(typescript@5.9.3) defu: 6.1.4 fs-extra: 11.2.0 - histoire: 1.0.0-beta.1(@types/node@24.11.2)(lightningcss@1.31.1)(sass-embedded@1.97.3)(sass@1.97.3)(terser@5.31.6)(vite@7.3.1(@types/node@24.11.2)(jiti@2.4.2)(lightningcss@1.31.1)(sass-embedded@1.97.3)(sass@1.97.3)(terser@5.31.6)(yaml@2.5.0))(yaml@2.5.0) + histoire: 1.0.0-beta.1(@types/node@24.12.0)(lightningcss@1.31.1)(sass-embedded@1.97.3)(sass@1.97.3)(terser@5.31.6)(vite@7.3.1(@types/node@24.12.0)(jiti@2.4.2)(lightningcss@1.31.1)(sass-embedded@1.97.3)(sass@1.97.3)(terser@5.31.6)(yaml@2.5.0))(yaml@2.5.0) pathe: 1.1.2 transitivePeerDependencies: - bare-buffer @@ -8309,21 +8309,21 @@ snapshots: - typescript - utf-8-validate - '@histoire/plugin-vue@1.0.0-beta.1(histoire@1.0.0-beta.1(@types/node@24.11.2)(lightningcss@1.31.1)(sass-embedded@1.97.3)(sass@1.97.3)(terser@5.31.6)(vite@7.3.1(@types/node@24.11.2)(jiti@2.4.2)(lightningcss@1.31.1)(sass-embedded@1.97.3)(sass@1.97.3)(terser@5.31.6)(yaml@2.5.0))(yaml@2.5.0))(vite@7.3.1(@types/node@24.11.2)(jiti@2.4.2)(lightningcss@1.31.1)(sass-embedded@1.97.3)(sass@1.97.3)(terser@5.31.6)(yaml@2.5.0))(vue@3.5.27(typescript@5.9.3))': + '@histoire/plugin-vue@1.0.0-beta.1(histoire@1.0.0-beta.1(@types/node@24.12.0)(lightningcss@1.31.1)(sass-embedded@1.97.3)(sass@1.97.3)(terser@5.31.6)(vite@7.3.1(@types/node@24.12.0)(jiti@2.4.2)(lightningcss@1.31.1)(sass-embedded@1.97.3)(sass@1.97.3)(terser@5.31.6)(yaml@2.5.0))(yaml@2.5.0))(vite@7.3.1(@types/node@24.12.0)(jiti@2.4.2)(lightningcss@1.31.1)(sass-embedded@1.97.3)(sass@1.97.3)(terser@5.31.6)(yaml@2.5.0))(vue@3.5.27(typescript@5.9.3))': dependencies: - '@histoire/controls': 1.0.0-beta.1(vite@7.3.1(@types/node@24.11.2)(jiti@2.4.2)(lightningcss@1.31.1)(sass-embedded@1.97.3)(sass@1.97.3)(terser@5.31.6)(yaml@2.5.0)) - '@histoire/shared': 1.0.0-beta.1(vite@7.3.1(@types/node@24.11.2)(jiti@2.4.2)(lightningcss@1.31.1)(sass-embedded@1.97.3)(sass@1.97.3)(terser@5.31.6)(yaml@2.5.0)) + '@histoire/controls': 1.0.0-beta.1(vite@7.3.1(@types/node@24.12.0)(jiti@2.4.2)(lightningcss@1.31.1)(sass-embedded@1.97.3)(sass@1.97.3)(terser@5.31.6)(yaml@2.5.0)) + '@histoire/shared': 1.0.0-beta.1(vite@7.3.1(@types/node@24.12.0)(jiti@2.4.2)(lightningcss@1.31.1)(sass-embedded@1.97.3)(sass@1.97.3)(terser@5.31.6)(yaml@2.5.0)) '@histoire/vendors': 1.0.0-beta.1 change-case: 5.4.4 globby: 14.1.0 - histoire: 1.0.0-beta.1(@types/node@24.11.2)(lightningcss@1.31.1)(sass-embedded@1.97.3)(sass@1.97.3)(terser@5.31.6)(vite@7.3.1(@types/node@24.11.2)(jiti@2.4.2)(lightningcss@1.31.1)(sass-embedded@1.97.3)(sass@1.97.3)(terser@5.31.6)(yaml@2.5.0))(yaml@2.5.0) + histoire: 1.0.0-beta.1(@types/node@24.12.0)(lightningcss@1.31.1)(sass-embedded@1.97.3)(sass@1.97.3)(terser@5.31.6)(vite@7.3.1(@types/node@24.12.0)(jiti@2.4.2)(lightningcss@1.31.1)(sass-embedded@1.97.3)(sass@1.97.3)(terser@5.31.6)(yaml@2.5.0))(yaml@2.5.0) launch-editor: 2.10.0 pathe: 1.1.2 vue: 3.5.27(typescript@5.9.3) transitivePeerDependencies: - vite - '@histoire/shared@1.0.0-beta.1(vite@7.3.1(@types/node@24.11.2)(jiti@2.4.2)(lightningcss@1.31.1)(sass-embedded@1.97.3)(sass@1.97.3)(terser@5.31.6)(yaml@2.5.0))': + '@histoire/shared@1.0.0-beta.1(vite@7.3.1(@types/node@24.12.0)(jiti@2.4.2)(lightningcss@1.31.1)(sass-embedded@1.97.3)(sass@1.97.3)(terser@5.31.6)(yaml@2.5.0))': dependencies: '@histoire/vendors': 1.0.0-beta.1 '@types/fs-extra': 11.0.4 @@ -8331,7 +8331,7 @@ snapshots: chokidar: 4.0.3 pathe: 1.1.2 picocolors: 1.1.1 - vite: 7.3.1(@types/node@24.11.2)(jiti@2.4.2)(lightningcss@1.31.1)(sass-embedded@1.97.3)(sass@1.97.3)(terser@5.31.6)(yaml@2.5.0) + vite: 7.3.1(@types/node@24.12.0)(jiti@2.4.2)(lightningcss@1.31.1)(sass-embedded@1.97.3)(sass@1.97.3)(terser@5.31.6)(yaml@2.5.0) '@histoire/vendors@1.0.0-beta.1': {} @@ -8946,12 +8946,12 @@ snapshots: '@tailwindcss/oxide-win32-arm64-msvc': 4.2.1 '@tailwindcss/oxide-win32-x64-msvc': 4.2.1 - '@tailwindcss/vite@4.2.1(vite@7.3.1(@types/node@24.11.2)(jiti@2.4.2)(lightningcss@1.31.1)(sass-embedded@1.97.3)(sass@1.97.3)(terser@5.31.6)(yaml@2.5.0))': + '@tailwindcss/vite@4.2.1(vite@7.3.1(@types/node@24.12.0)(jiti@2.4.2)(lightningcss@1.31.1)(sass-embedded@1.97.3)(sass@1.97.3)(terser@5.31.6)(yaml@2.5.0))': dependencies: '@tailwindcss/node': 4.2.1 '@tailwindcss/oxide': 4.2.1 tailwindcss: 4.2.1 - vite: 7.3.1(@types/node@24.11.2)(jiti@2.4.2)(lightningcss@1.31.1)(sass-embedded@1.97.3)(sass@1.97.3)(terser@5.31.6)(yaml@2.5.0) + vite: 7.3.1(@types/node@24.12.0)(jiti@2.4.2)(lightningcss@1.31.1)(sass-embedded@1.97.3)(sass@1.97.3)(terser@5.31.6)(yaml@2.5.0) '@tiptap/core@3.17.0(@tiptap/pm@3.17.0)': dependencies: @@ -9176,7 +9176,7 @@ snapshots: '@types/fs-extra@11.0.4': dependencies: '@types/jsonfile': 6.1.4 - '@types/node': 24.11.2 + '@types/node': 24.12.0 '@types/hast@3.0.4': dependencies: @@ -9188,7 +9188,7 @@ snapshots: '@types/jsonfile@6.1.4': dependencies: - '@types/node': 24.11.2 + '@types/node': 24.12.0 '@types/linkify-it@5.0.0': {} @@ -9205,7 +9205,7 @@ snapshots: '@types/minimist@1.2.5': {} - '@types/node@24.11.2': + '@types/node@24.12.0': dependencies: undici-types: 7.16.0 @@ -9229,11 +9229,11 @@ snapshots: '@types/ws@8.18.1': dependencies: - '@types/node': 24.11.2 + '@types/node': 24.12.0 '@types/yauzl@2.10.3': dependencies: - '@types/node': 24.11.2 + '@types/node': 24.12.0 optional: true '@typescript-eslint/eslint-plugin@8.56.0(@typescript-eslint/parser@8.56.0(eslint@9.39.3(jiti@2.4.2))(typescript@5.9.3))(eslint@9.39.3(jiti@2.4.2))(typescript@5.9.3)': @@ -9460,10 +9460,10 @@ snapshots: '@ungap/structured-clone@1.3.0': {} - '@vitejs/plugin-vue@6.0.4(vite@7.3.1(@types/node@24.11.2)(jiti@2.4.2)(lightningcss@1.31.1)(sass-embedded@1.97.3)(sass@1.97.3)(terser@5.31.6)(yaml@2.5.0))(vue@3.5.27(typescript@5.9.3))': + '@vitejs/plugin-vue@6.0.4(vite@7.3.1(@types/node@24.12.0)(jiti@2.4.2)(lightningcss@1.31.1)(sass-embedded@1.97.3)(sass@1.97.3)(terser@5.31.6)(yaml@2.5.0))(vue@3.5.27(typescript@5.9.3))': dependencies: '@rolldown/pluginutils': 1.0.0-rc.2 - vite: 7.3.1(@types/node@24.11.2)(jiti@2.4.2)(lightningcss@1.31.1)(sass-embedded@1.97.3)(sass@1.97.3)(terser@5.31.6)(yaml@2.5.0) + vite: 7.3.1(@types/node@24.12.0)(jiti@2.4.2)(lightningcss@1.31.1)(sass-embedded@1.97.3)(sass@1.97.3)(terser@5.31.6)(yaml@2.5.0) vue: 3.5.27(typescript@5.9.3) '@vitest/expect@4.0.18': @@ -9475,13 +9475,13 @@ snapshots: chai: 6.2.2 tinyrainbow: 3.0.3 - '@vitest/mocker@4.0.18(vite@7.3.1(@types/node@24.11.2)(jiti@2.4.2)(lightningcss@1.31.1)(sass-embedded@1.97.3)(sass@1.97.3)(terser@5.31.6)(yaml@2.5.0))': + '@vitest/mocker@4.0.18(vite@7.3.1(@types/node@24.12.0)(jiti@2.4.2)(lightningcss@1.31.1)(sass-embedded@1.97.3)(sass@1.97.3)(terser@5.31.6)(yaml@2.5.0))': dependencies: '@vitest/spy': 4.0.18 estree-walker: 3.0.3 magic-string: 0.30.21 optionalDependencies: - vite: 7.3.1(@types/node@24.11.2)(jiti@2.4.2)(lightningcss@1.31.1)(sass-embedded@1.97.3)(sass@1.97.3)(terser@5.31.6)(yaml@2.5.0) + vite: 7.3.1(@types/node@24.12.0)(jiti@2.4.2)(lightningcss@1.31.1)(sass-embedded@1.97.3)(sass@1.97.3)(terser@5.31.6)(yaml@2.5.0) '@vitest/pretty-format@4.0.18': dependencies: @@ -9795,7 +9795,7 @@ snapshots: autoprefixer@10.4.27(postcss@8.5.8): dependencies: browserslist: 4.28.1 - caniuse-lite: 1.0.30001776 + caniuse-lite: 1.0.30001777 fraction.js: 5.3.4 picocolors: 1.1.1 postcss: 8.5.8 @@ -9914,7 +9914,7 @@ snapshots: browserslist@4.28.1: dependencies: baseline-browser-mapping: 2.9.4 - caniuse-lite: 1.0.30001776 + caniuse-lite: 1.0.30001777 electron-to-chromium: 1.5.266 node-releases: 2.0.27 update-browserslist-db: 1.2.2(browserslist@4.28.1) @@ -9976,7 +9976,7 @@ snapshots: camelcase@8.0.0: {} - caniuse-lite@1.0.30001776: {} + caniuse-lite@1.0.30001777: {} capture-website@4.2.0(typescript@5.9.3): dependencies: @@ -10956,7 +10956,7 @@ snapshots: happy-dom@20.8.3: dependencies: - '@types/node': 24.11.2 + '@types/node': 24.12.0 '@types/whatwg-mimetype': 3.0.2 '@types/ws': 8.18.1 entities: 7.0.1 @@ -11014,12 +11014,12 @@ snapshots: highlight.js@11.11.1: {} - histoire@1.0.0-beta.1(@types/node@24.11.2)(lightningcss@1.31.1)(sass-embedded@1.97.3)(sass@1.97.3)(terser@5.31.6)(vite@7.3.1(@types/node@24.11.2)(jiti@2.4.2)(lightningcss@1.31.1)(sass-embedded@1.97.3)(sass@1.97.3)(terser@5.31.6)(yaml@2.5.0))(yaml@2.5.0): + histoire@1.0.0-beta.1(@types/node@24.12.0)(lightningcss@1.31.1)(sass-embedded@1.97.3)(sass@1.97.3)(terser@5.31.6)(vite@7.3.1(@types/node@24.12.0)(jiti@2.4.2)(lightningcss@1.31.1)(sass-embedded@1.97.3)(sass@1.97.3)(terser@5.31.6)(yaml@2.5.0))(yaml@2.5.0): dependencies: '@akryum/tinypool': 0.3.1 - '@histoire/app': 1.0.0-beta.1(vite@7.3.1(@types/node@24.11.2)(jiti@2.4.2)(lightningcss@1.31.1)(sass-embedded@1.97.3)(sass@1.97.3)(terser@5.31.6)(yaml@2.5.0)) - '@histoire/controls': 1.0.0-beta.1(vite@7.3.1(@types/node@24.11.2)(jiti@2.4.2)(lightningcss@1.31.1)(sass-embedded@1.97.3)(sass@1.97.3)(terser@5.31.6)(yaml@2.5.0)) - '@histoire/shared': 1.0.0-beta.1(vite@7.3.1(@types/node@24.11.2)(jiti@2.4.2)(lightningcss@1.31.1)(sass-embedded@1.97.3)(sass@1.97.3)(terser@5.31.6)(yaml@2.5.0)) + '@histoire/app': 1.0.0-beta.1(vite@7.3.1(@types/node@24.12.0)(jiti@2.4.2)(lightningcss@1.31.1)(sass-embedded@1.97.3)(sass@1.97.3)(terser@5.31.6)(yaml@2.5.0)) + '@histoire/controls': 1.0.0-beta.1(vite@7.3.1(@types/node@24.12.0)(jiti@2.4.2)(lightningcss@1.31.1)(sass-embedded@1.97.3)(sass@1.97.3)(terser@5.31.6)(yaml@2.5.0)) + '@histoire/shared': 1.0.0-beta.1(vite@7.3.1(@types/node@24.12.0)(jiti@2.4.2)(lightningcss@1.31.1)(sass-embedded@1.97.3)(sass@1.97.3)(terser@5.31.6)(yaml@2.5.0)) '@histoire/vendors': 1.0.0-beta.1 '@types/markdown-it': 14.1.2 birpc: 0.2.19 @@ -11044,8 +11044,8 @@ snapshots: sade: 1.8.1 shiki: 3.2.1 sirv: 3.0.2 - vite: 7.3.1(@types/node@24.11.2)(jiti@2.4.2)(lightningcss@1.31.1)(sass-embedded@1.97.3)(sass@1.97.3)(terser@5.31.6)(yaml@2.5.0) - vite-node: 3.2.4(@types/node@24.11.2)(jiti@2.4.2)(lightningcss@1.31.1)(sass-embedded@1.97.3)(sass@1.97.3)(terser@5.31.6)(yaml@2.5.0) + vite: 7.3.1(@types/node@24.12.0)(jiti@2.4.2)(lightningcss@1.31.1)(sass-embedded@1.97.3)(sass@1.97.3)(terser@5.31.6)(yaml@2.5.0) + vite-node: 3.2.4(@types/node@24.12.0)(jiti@2.4.2)(lightningcss@1.31.1)(sass-embedded@1.97.3)(sass@1.97.3)(terser@5.31.6)(yaml@2.5.0) transitivePeerDependencies: - '@exodus/crypto' - '@types/node' @@ -13416,23 +13416,23 @@ snapshots: '@types/unist': 3.0.3 vfile-message: 4.0.2 - vite-dev-rpc@1.1.0(vite@7.3.1(@types/node@24.11.2)(jiti@2.4.2)(lightningcss@1.31.1)(sass-embedded@1.97.3)(sass@1.97.3)(terser@5.31.6)(yaml@2.5.0)): + vite-dev-rpc@1.1.0(vite@7.3.1(@types/node@24.12.0)(jiti@2.4.2)(lightningcss@1.31.1)(sass-embedded@1.97.3)(sass@1.97.3)(terser@5.31.6)(yaml@2.5.0)): dependencies: birpc: 2.6.1 - vite: 7.3.1(@types/node@24.11.2)(jiti@2.4.2)(lightningcss@1.31.1)(sass-embedded@1.97.3)(sass@1.97.3)(terser@5.31.6)(yaml@2.5.0) - vite-hot-client: 2.1.0(vite@7.3.1(@types/node@24.11.2)(jiti@2.4.2)(lightningcss@1.31.1)(sass-embedded@1.97.3)(sass@1.97.3)(terser@5.31.6)(yaml@2.5.0)) + vite: 7.3.1(@types/node@24.12.0)(jiti@2.4.2)(lightningcss@1.31.1)(sass-embedded@1.97.3)(sass@1.97.3)(terser@5.31.6)(yaml@2.5.0) + vite-hot-client: 2.1.0(vite@7.3.1(@types/node@24.12.0)(jiti@2.4.2)(lightningcss@1.31.1)(sass-embedded@1.97.3)(sass@1.97.3)(terser@5.31.6)(yaml@2.5.0)) - vite-hot-client@2.1.0(vite@7.3.1(@types/node@24.11.2)(jiti@2.4.2)(lightningcss@1.31.1)(sass-embedded@1.97.3)(sass@1.97.3)(terser@5.31.6)(yaml@2.5.0)): + vite-hot-client@2.1.0(vite@7.3.1(@types/node@24.12.0)(jiti@2.4.2)(lightningcss@1.31.1)(sass-embedded@1.97.3)(sass@1.97.3)(terser@5.31.6)(yaml@2.5.0)): dependencies: - vite: 7.3.1(@types/node@24.11.2)(jiti@2.4.2)(lightningcss@1.31.1)(sass-embedded@1.97.3)(sass@1.97.3)(terser@5.31.6)(yaml@2.5.0) + vite: 7.3.1(@types/node@24.12.0)(jiti@2.4.2)(lightningcss@1.31.1)(sass-embedded@1.97.3)(sass@1.97.3)(terser@5.31.6)(yaml@2.5.0) - vite-node@3.2.4(@types/node@24.11.2)(jiti@2.4.2)(lightningcss@1.31.1)(sass-embedded@1.97.3)(sass@1.97.3)(terser@5.31.6)(yaml@2.5.0): + vite-node@3.2.4(@types/node@24.12.0)(jiti@2.4.2)(lightningcss@1.31.1)(sass-embedded@1.97.3)(sass@1.97.3)(terser@5.31.6)(yaml@2.5.0): dependencies: cac: 6.7.14 debug: 4.4.3 es-module-lexer: 1.7.0 pathe: 2.0.3 - vite: 7.3.1(@types/node@24.11.2)(jiti@2.4.2)(lightningcss@1.31.1)(sass-embedded@1.97.3)(sass@1.97.3)(terser@5.31.6)(yaml@2.5.0) + vite: 7.3.1(@types/node@24.12.0)(jiti@2.4.2)(lightningcss@1.31.1)(sass-embedded@1.97.3)(sass@1.97.3)(terser@5.31.6)(yaml@2.5.0) transitivePeerDependencies: - '@types/node' - jiti @@ -13447,7 +13447,7 @@ snapshots: - tsx - yaml - vite-plugin-inspect@11.3.3(vite@7.3.1(@types/node@24.11.2)(jiti@2.4.2)(lightningcss@1.31.1)(sass-embedded@1.97.3)(sass@1.97.3)(terser@5.31.6)(yaml@2.5.0)): + vite-plugin-inspect@11.3.3(vite@7.3.1(@types/node@24.12.0)(jiti@2.4.2)(lightningcss@1.31.1)(sass-embedded@1.97.3)(sass@1.97.3)(terser@5.31.6)(yaml@2.5.0)): dependencies: ansis: 4.1.0 debug: 4.4.3 @@ -13457,37 +13457,37 @@ snapshots: perfect-debounce: 2.0.0 sirv: 3.0.2 unplugin-utils: 0.3.0 - vite: 7.3.1(@types/node@24.11.2)(jiti@2.4.2)(lightningcss@1.31.1)(sass-embedded@1.97.3)(sass@1.97.3)(terser@5.31.6)(yaml@2.5.0) - vite-dev-rpc: 1.1.0(vite@7.3.1(@types/node@24.11.2)(jiti@2.4.2)(lightningcss@1.31.1)(sass-embedded@1.97.3)(sass@1.97.3)(terser@5.31.6)(yaml@2.5.0)) + vite: 7.3.1(@types/node@24.12.0)(jiti@2.4.2)(lightningcss@1.31.1)(sass-embedded@1.97.3)(sass@1.97.3)(terser@5.31.6)(yaml@2.5.0) + vite-dev-rpc: 1.1.0(vite@7.3.1(@types/node@24.12.0)(jiti@2.4.2)(lightningcss@1.31.1)(sass-embedded@1.97.3)(sass@1.97.3)(terser@5.31.6)(yaml@2.5.0)) transitivePeerDependencies: - supports-color - vite-plugin-pwa@1.2.0(vite@7.3.1(@types/node@24.11.2)(jiti@2.4.2)(lightningcss@1.31.1)(sass-embedded@1.97.3)(sass@1.97.3)(terser@5.31.6)(yaml@2.5.0))(workbox-build@7.4.0)(workbox-window@7.4.0): + vite-plugin-pwa@1.2.0(vite@7.3.1(@types/node@24.12.0)(jiti@2.4.2)(lightningcss@1.31.1)(sass-embedded@1.97.3)(sass@1.97.3)(terser@5.31.6)(yaml@2.5.0))(workbox-build@7.4.0)(workbox-window@7.4.0): dependencies: debug: 4.4.3 pretty-bytes: 6.1.1 tinyglobby: 0.2.15 - vite: 7.3.1(@types/node@24.11.2)(jiti@2.4.2)(lightningcss@1.31.1)(sass-embedded@1.97.3)(sass@1.97.3)(terser@5.31.6)(yaml@2.5.0) + vite: 7.3.1(@types/node@24.12.0)(jiti@2.4.2)(lightningcss@1.31.1)(sass-embedded@1.97.3)(sass@1.97.3)(terser@5.31.6)(yaml@2.5.0) workbox-build: 7.4.0 workbox-window: 7.4.0 transitivePeerDependencies: - supports-color - vite-plugin-vue-devtools@8.0.7(vite@7.3.1(@types/node@24.11.2)(jiti@2.4.2)(lightningcss@1.31.1)(sass-embedded@1.97.3)(sass@1.97.3)(terser@5.31.6)(yaml@2.5.0))(vue@3.5.27(typescript@5.9.3)): + vite-plugin-vue-devtools@8.0.7(vite@7.3.1(@types/node@24.12.0)(jiti@2.4.2)(lightningcss@1.31.1)(sass-embedded@1.97.3)(sass@1.97.3)(terser@5.31.6)(yaml@2.5.0))(vue@3.5.27(typescript@5.9.3)): dependencies: '@vue/devtools-core': 8.0.7(vue@3.5.27(typescript@5.9.3)) '@vue/devtools-kit': 8.0.7 '@vue/devtools-shared': 8.0.7 sirv: 3.0.2 - vite: 7.3.1(@types/node@24.11.2)(jiti@2.4.2)(lightningcss@1.31.1)(sass-embedded@1.97.3)(sass@1.97.3)(terser@5.31.6)(yaml@2.5.0) - vite-plugin-inspect: 11.3.3(vite@7.3.1(@types/node@24.11.2)(jiti@2.4.2)(lightningcss@1.31.1)(sass-embedded@1.97.3)(sass@1.97.3)(terser@5.31.6)(yaml@2.5.0)) - vite-plugin-vue-inspector: 5.3.2(vite@7.3.1(@types/node@24.11.2)(jiti@2.4.2)(lightningcss@1.31.1)(sass-embedded@1.97.3)(sass@1.97.3)(terser@5.31.6)(yaml@2.5.0)) + vite: 7.3.1(@types/node@24.12.0)(jiti@2.4.2)(lightningcss@1.31.1)(sass-embedded@1.97.3)(sass@1.97.3)(terser@5.31.6)(yaml@2.5.0) + vite-plugin-inspect: 11.3.3(vite@7.3.1(@types/node@24.12.0)(jiti@2.4.2)(lightningcss@1.31.1)(sass-embedded@1.97.3)(sass@1.97.3)(terser@5.31.6)(yaml@2.5.0)) + vite-plugin-vue-inspector: 5.3.2(vite@7.3.1(@types/node@24.12.0)(jiti@2.4.2)(lightningcss@1.31.1)(sass-embedded@1.97.3)(sass@1.97.3)(terser@5.31.6)(yaml@2.5.0)) transitivePeerDependencies: - '@nuxt/kit' - supports-color - vue - vite-plugin-vue-inspector@5.3.2(vite@7.3.1(@types/node@24.11.2)(jiti@2.4.2)(lightningcss@1.31.1)(sass-embedded@1.97.3)(sass@1.97.3)(terser@5.31.6)(yaml@2.5.0)): + vite-plugin-vue-inspector@5.3.2(vite@7.3.1(@types/node@24.12.0)(jiti@2.4.2)(lightningcss@1.31.1)(sass-embedded@1.97.3)(sass@1.97.3)(terser@5.31.6)(yaml@2.5.0)): dependencies: '@babel/core': 7.26.0 '@babel/plugin-proposal-decorators': 7.25.9(@babel/core@7.26.0) @@ -13498,7 +13498,7 @@ snapshots: '@vue/compiler-dom': 3.5.27 kolorist: 1.8.0 magic-string: 0.30.21 - vite: 7.3.1(@types/node@24.11.2)(jiti@2.4.2)(lightningcss@1.31.1)(sass-embedded@1.97.3)(sass@1.97.3)(terser@5.31.6)(yaml@2.5.0) + vite: 7.3.1(@types/node@24.12.0)(jiti@2.4.2)(lightningcss@1.31.1)(sass-embedded@1.97.3)(sass@1.97.3)(terser@5.31.6)(yaml@2.5.0) transitivePeerDependencies: - supports-color @@ -13510,7 +13510,7 @@ snapshots: transitivePeerDependencies: - supports-color - vite@7.3.1(@types/node@24.11.2)(jiti@2.4.2)(lightningcss@1.31.1)(sass-embedded@1.97.3)(sass@1.97.3)(terser@5.31.6)(yaml@2.5.0): + vite@7.3.1(@types/node@24.12.0)(jiti@2.4.2)(lightningcss@1.31.1)(sass-embedded@1.97.3)(sass@1.97.3)(terser@5.31.6)(yaml@2.5.0): dependencies: esbuild: 0.27.3 fdir: 6.5.0(picomatch@4.0.3) @@ -13519,7 +13519,7 @@ snapshots: rollup: 4.59.0 tinyglobby: 0.2.15 optionalDependencies: - '@types/node': 24.11.2 + '@types/node': 24.12.0 fsevents: 2.3.3 jiti: 2.4.2 lightningcss: 1.31.1 @@ -13528,10 +13528,10 @@ snapshots: terser: 5.31.6 yaml: 2.5.0 - vitest@4.0.18(@types/node@24.11.2)(happy-dom@20.8.3)(jiti@2.4.2)(jsdom@27.4.0)(lightningcss@1.31.1)(sass-embedded@1.97.3)(sass@1.97.3)(terser@5.31.6)(yaml@2.5.0): + vitest@4.0.18(@types/node@24.12.0)(happy-dom@20.8.3)(jiti@2.4.2)(jsdom@27.4.0)(lightningcss@1.31.1)(sass-embedded@1.97.3)(sass@1.97.3)(terser@5.31.6)(yaml@2.5.0): dependencies: '@vitest/expect': 4.0.18 - '@vitest/mocker': 4.0.18(vite@7.3.1(@types/node@24.11.2)(jiti@2.4.2)(lightningcss@1.31.1)(sass-embedded@1.97.3)(sass@1.97.3)(terser@5.31.6)(yaml@2.5.0)) + '@vitest/mocker': 4.0.18(vite@7.3.1(@types/node@24.12.0)(jiti@2.4.2)(lightningcss@1.31.1)(sass-embedded@1.97.3)(sass@1.97.3)(terser@5.31.6)(yaml@2.5.0)) '@vitest/pretty-format': 4.0.18 '@vitest/runner': 4.0.18 '@vitest/snapshot': 4.0.18 @@ -13548,10 +13548,10 @@ snapshots: tinyexec: 1.0.2 tinyglobby: 0.2.15 tinyrainbow: 3.0.3 - vite: 7.3.1(@types/node@24.11.2)(jiti@2.4.2)(lightningcss@1.31.1)(sass-embedded@1.97.3)(sass@1.97.3)(terser@5.31.6)(yaml@2.5.0) + vite: 7.3.1(@types/node@24.12.0)(jiti@2.4.2)(lightningcss@1.31.1)(sass-embedded@1.97.3)(sass@1.97.3)(terser@5.31.6)(yaml@2.5.0) why-is-node-running: 2.3.0 optionalDependencies: - '@types/node': 24.11.2 + '@types/node': 24.12.0 happy-dom: 20.8.3 jsdom: 27.4.0 transitivePeerDependencies: From cea8c7807d060e0a187c37c80ba42d02d4aa7637 Mon Sep 17 00:00:00 2001 From: John Starich Date: Fri, 6 Mar 2026 00:56:27 -0600 Subject: [PATCH 027/142] refactor: enable golangci-lint on magefile, fix errors --- .golangci.yml | 6 ++ magefile.go | 234 +++++++++++++++++++++++++++++--------------------- 2 files changed, 141 insertions(+), 99 deletions(-) diff --git a/.golangci.yml b/.golangci.yml index d4afbf288..28f46f670 100644 --- a/.golangci.yml +++ b/.golangci.yml @@ -1,6 +1,8 @@ version: "2" run: tests: true + build-tags: + - mage linters: enable: - asasalint @@ -146,6 +148,10 @@ linters: - linters: - revive text: 'var-naming: avoid package names that conflict with Go standard library package names' + - linters: + - err113 + path: magefile.go + text: 'do not define dynamic errors, use wrapped static errors instead:' paths: - third_party$ - builtin$ diff --git a/magefile.go b/magefile.go index ba5634527..45943bb13 100644 --- a/magefile.go +++ b/magefile.go @@ -24,6 +24,7 @@ import ( "context" "crypto/sha256" "encoding/json" + "errors" "fmt" "io" "io/fs" @@ -60,7 +61,7 @@ var ( PkgVersion = "unstable" // Aliases are mage aliases of targets - Aliases = map[string]interface{}{ + Aliases = map[string]any{ "build": Build.Build, "check:got-swag": Check.GotSwag, "release": Release.Release, @@ -86,14 +87,15 @@ func goDetectVerboseFlag() string { return fmt.Sprintf("-v=%t", mg.Verbose()) } -func runCmdWithOutput(name string, arg ...string) (output []byte, err error) { - cmd := exec.Command(name, arg...) +func runGitCommandWithOutput(arg ...string) (output []byte, err error) { + cmd := exec.Command("git", arg...) output, err = cmd.Output() if err != nil { - if ee, is := err.(*exec.ExitError); is { - return nil, fmt.Errorf("error running command: %s, %s", string(ee.Stderr), err) + var ee *exec.ExitError + if errors.As(err, &ee) { + return nil, fmt.Errorf("error running command: %s, %w", string(ee.Stderr), err) } - return nil, fmt.Errorf("error running command: %s", err) + return nil, fmt.Errorf("error running command: %w", err) } return output, nil @@ -130,7 +132,7 @@ func getRawVersionNumber() (version string, err error) { return strings.Replace(os.Getenv("DRONE_BRANCH"), "release/v", "", 1), nil } - versionBytes, err := runCmdWithOutput("git", "describe", "--tags", "--always", "--abbrev=10") + versionBytes, err := runGitCommandWithOutput("describe", "--tags", "--always", "--abbrev=10") return string(versionBytes), err } @@ -204,15 +206,15 @@ func runAndStreamOutput(cmd string, args ...string) error { // Will check if the tool exists and if not install it from the provided import path // If any errors occur, it will exit with a status code of 1. -func checkAndInstallGoTool(tool, importPath string) { +func checkAndInstallGoTool(tool, importPath string) error { if err := exec.Command(tool).Run(); err != nil && strings.Contains(err.Error(), "executable file not found") { fmt.Printf("%s not installed, installing %s...\n", tool, importPath) - if err := exec.Command("go", "install", goDetectVerboseFlag(), importPath).Run(); err != nil { - fmt.Printf("Error installing %s\n", tool) - os.Exit(1) + if err := exec.Command("go", "install", goDetectVerboseFlag(), importPath).Run(); err != nil { //nolint:gosec // Every caller to checkAndInstallGoTool is hard-coded at time of writing, so no injection possible. + return fmt.Errorf("error installing %s: %w", tool, err) } fmt.Println("Installed.") } + return nil } // Calculates a hash of a file @@ -269,19 +271,19 @@ func copyFile(src, dst string) error { func moveFile(src, dst string) error { inputFile, err := os.Open(src) if err != nil { - return fmt.Errorf("couldn't open source file: %s", err) + return fmt.Errorf("couldn't open source file: %w", err) } defer inputFile.Close() outputFile, err := os.Create(dst) if err != nil { - return fmt.Errorf("couldn't open dest file: %s", err) + return fmt.Errorf("couldn't open dest file: %w", err) } defer outputFile.Close() _, err = io.Copy(outputFile, inputFile) if err != nil { - return fmt.Errorf("writing to output file failed: %s", err) + return fmt.Errorf("writing to output file failed: %w", err) } // Make sure to copy copy the permissions of the original file as well @@ -297,7 +299,7 @@ func moveFile(src, dst string) error { // The copy was successful, so now delete the original file err = os.Remove(src) if err != nil { - return fmt.Errorf("failed removing original file: %s", err) + return fmt.Errorf("failed removing original file: %w", err) } return nil } @@ -316,7 +318,7 @@ func appendToFile(filename, content string) error { const InfoColor = "\033[1;32m%s\033[0m" -func printSuccess(text string, args ...interface{}) { +func printSuccess(text string, args ...any) { text = fmt.Sprintf(text, args...) fmt.Printf(InfoColor+"\n", text) } @@ -346,14 +348,17 @@ func setProcessGroup(cmd *exec.Cmd) { } // killProcessGroup sends a signal to the entire process group of the given command. -func killProcessGroup(cmd *exec.Cmd) { - if cmd.Process != nil { - pgid, err := syscall.Getpgid(cmd.Process.Pid) - if err == nil { - syscall.Kill(-pgid, syscall.SIGTERM) - } - cmd.Wait() +func killProcessGroup(cmd *exec.Cmd) error { + if cmd.Process == nil { + return nil } + if pgid, err := syscall.Getpgid(cmd.Process.Pid); err == nil { // use best-effort to kill full process group + err = syscall.Kill(-pgid, syscall.SIGTERM) + if err != nil { + return err + } + } + return cmd.Wait() } // waitForHTTP polls a URL until it returns a 200 status or the timeout expires. @@ -525,7 +530,9 @@ func (Test) E2E(args string) error { } defer func() { fmt.Println("\n--- Stopping API server ---") - killProcessGroup(apiCmd) + if err := killProcessGroup(apiCmd); err != nil { + fmt.Println("Failed to stop API server:", err) + } }() // Wait for API to be ready @@ -549,7 +556,7 @@ func (Test) E2E(args string) error { // Serve the built frontend with vite preview (static, no file watchers) fmt.Println("\n--- Starting frontend preview server ---") - frontendCmd := exec.Command("pnpm", "preview:dev", "--port", strconv.Itoa(frontendPort)) + frontendCmd := exec.Command("pnpm", "preview:dev", "--port", strconv.Itoa(frontendPort)) //nolint:gosec // This mage task runs end to end tests with environment-based configuration, it must use the port environment variable to suit its current environment. frontendCmd.Dir = "frontend" frontendCmd.Stdout = os.Stdout frontendCmd.Stderr = os.Stderr @@ -559,7 +566,9 @@ func (Test) E2E(args string) error { } defer func() { fmt.Println("\n--- Stopping frontend preview server ---") - killProcessGroup(frontendCmd) + if err := killProcessGroup(frontendCmd); err != nil { + fmt.Println("Failed to stop API server:", err) + } }() // Wait for frontend to be ready @@ -600,7 +609,7 @@ func (Test) E2E(args string) error { type Check mg.Namespace // GotSwag checks if the swagger docs need to be re-generated from the code annotations -func (Check) GotSwag() { +func (Check) GotSwag() error { mg.Deps(initVars) // The check is pretty cheaply done: We take the hash of the swagger.json file, generate the docs, // hash the file again and compare the two hashes to see if anything changed. If that's the case, @@ -610,27 +619,26 @@ func (Check) GotSwag() { // docs after the check. This behaviour is good enough for ci though. oldHash, err := calculateSha256FileHash("./pkg/swagger/swagger.json") if err != nil { - fmt.Printf("Error getting old hash of the swagger docs: %s", err) - os.Exit(1) + return fmt.Errorf("error getting old hash of the swagger docs: %w", err) } - (Generate{}).SwaggerDocs() + if generateErr := (Generate{}).SwaggerDocs(); generateErr != nil { + return generateErr + } newHash, err := calculateSha256FileHash("./pkg/swagger/swagger.json") if err != nil { - fmt.Printf("Error getting new hash of the swagger docs: %s", err) - os.Exit(1) + return fmt.Errorf("error getting new hash of the swagger docs: %w", err) } if oldHash != newHash { - fmt.Println("Swagger docs are not up to date.") - fmt.Println("Please run 'mage generate:swagger-docs' and commit the result.") - os.Exit(1) + return fmt.Errorf("swagger docs are not up to date: run 'mage generate:swagger-docs' and commit the result") } + return nil } // Translations checks if all translation keys used in the code exist in the English translation file -func (Check) Translations() { +func (Check) Translations() error { mg.Deps(initVars) fmt.Println("Checking for missing translation keys...") @@ -638,8 +646,7 @@ func (Check) Translations() { translationFile := "./pkg/i18n/lang/en.json" translations, err := loadTranslations(translationFile) if err != nil { - fmt.Printf("Error loading translations: %v\n", err) - os.Exit(1) + return fmt.Errorf("error loading translations: %w", err) } fmt.Printf("Loaded %d translation keys from %s\n", len(translations), translationFile) @@ -647,8 +654,7 @@ func (Check) Translations() { // Extract keys from codebase keys, err := walkCodebaseForTranslationKeys(".") if err != nil { - fmt.Printf("Error walking codebase: %v\n", err) - os.Exit(1) + return fmt.Errorf("error walking codebase: %w", err) } fmt.Printf("Found %d translation keys in the codebase\n", len(keys)) @@ -663,17 +669,18 @@ func (Check) Translations() { // Print results if len(missingKeys) > 0 { - fmt.Printf("\nFound %d missing translation keys:\n", len(missingKeys)) + var errs []error for key, occurrences := range missingKeys { - fmt.Printf("\nKey: %s\n", key) + var keyErrs []error for _, occurrence := range occurrences { - fmt.Printf(" - %s:%d\n", occurrence.FilePath, occurrence.Line) + keyErrs = append(keyErrs, fmt.Errorf("- %s:%d", occurrence.FilePath, occurrence.Line)) } + errs = append(errs, fmt.Errorf("missing key %s in files:\n%w", key, errors.Join(keyErrs...))) } - os.Exit(1) - } else { - printSuccess("All translation keys are present in the translation file!") + return fmt.Errorf("found %d missing translation keys:\n%w", len(missingKeys), errors.Join(errs...)) } + printSuccess("All translation keys are present in the translation file!") + return nil } // TranslationKey represents a translation key found in the code @@ -687,12 +694,12 @@ type TranslationKey struct { func loadTranslations(filePath string) (map[string]bool, error) { data, err := os.ReadFile(filePath) if err != nil { - return nil, fmt.Errorf("error reading translation file: %v", err) + return nil, fmt.Errorf("error reading translation file: %w", err) } - var translationsMap map[string]interface{} + var translationsMap map[string]any if err := json.Unmarshal(data, &translationsMap); err != nil { - return nil, fmt.Errorf("error parsing JSON: %v", err) + return nil, fmt.Errorf("error parsing JSON: %w", err) } // Flatten the nested structure @@ -703,7 +710,7 @@ func loadTranslations(filePath string) (map[string]bool, error) { } // flattenTranslations recursively flattens a nested map structure into a flat map with dot-separated keys -func flattenTranslations(prefix string, src map[string]interface{}, dest map[string]bool) { +func flattenTranslations(prefix string, src map[string]any, dest map[string]bool) { for k, v := range src { key := k if prefix != "" { @@ -713,7 +720,7 @@ func flattenTranslations(prefix string, src map[string]interface{}, dest map[str switch vv := v.(type) { case string: dest[key] = true - case map[string]interface{}: + case map[string]any: flattenTranslations(key, vv, dest) } } @@ -756,7 +763,7 @@ func extractTranslationKeysFromFile(filePath string) ([]TranslationKey, error) { // Read the file content content, err := os.ReadFile(filePath) if err != nil { - return nil, fmt.Errorf("error reading file %s: %v", filePath, err) + return nil, fmt.Errorf("error reading file %s: %w", filePath, err) } var keys []TranslationKey @@ -786,22 +793,25 @@ func extractTranslationKeysFromFile(filePath string) ([]TranslationKey, error) { return keys, nil } -func checkGolangCiLintInstalled() { +func checkGolangCiLintInstalled() error { mg.Deps(initVars) if err := exec.Command("golangci-lint").Run(); err != nil && strings.Contains(err.Error(), "executable file not found") { - fmt.Println("Please manually install golangci-lint by running") - fmt.Println("curl -sSfL https://raw.githubusercontent.com/golangci/golangci-lint/master/install.sh | sh -s -- -b $(go env GOPATH)/bin v2.4.0") - os.Exit(1) + return fmt.Errorf("golangci-lint executable failed to run, please manually install golangci-lint by running the command: curl -sSfL https://raw.githubusercontent.com/golangci/golangci-lint/master/install.sh | sh -s -- -b $(go env GOPATH)/bin v2.4.0") } + return nil } func (Check) Golangci() error { - checkGolangCiLintInstalled() + if err := checkGolangCiLintInstalled(); err != nil { + return err + } return runAndStreamOutput("golangci-lint", "run") } func (Check) GolangciFix() error { - checkGolangCiLintInstalled() + if err := checkGolangCiLintInstalled(); err != nil { + return err + } return runAndStreamOutput("golangci-lint", "run", "--fix") } @@ -842,8 +852,7 @@ func (Build) Build() error { distPath := filepath.Join("frontend", "dist") if _, err := os.Stat(distPath); os.IsNotExist(err) { if err := os.MkdirAll(distPath, 0o755); err != nil { - fmt.Printf("Error creating %s: %s\n", distPath, err) - os.Exit(1) + return fmt.Errorf("error creating %s: %w", distPath, err) } } @@ -851,8 +860,7 @@ func (Build) Build() error { if _, err := os.Stat(indexFile); os.IsNotExist(err) { f, err := os.Create(indexFile) if err != nil { - fmt.Printf("Error creating %s: %s\n", indexFile, err) - os.Exit(1) + return fmt.Errorf("error creating %s: %w", indexFile, err) } f.Close() fmt.Printf("Warning: %s not found, created empty file\n", indexFile) @@ -928,7 +936,9 @@ func (Release) Dirs() error { func prepareXgo() error { mg.Deps(initVars) - checkAndInstallGoTool("xgo", "src.techknowlogick.com/xgo") + if err := checkAndInstallGoTool("xgo", "src.techknowlogick.com/xgo"); err != nil { + return err + } fmt.Println("Pulling latest xgo docker image...") return runAndStreamOutput("docker", "pull", "ghcr.io/techknowlogick/xgo:latest") @@ -936,7 +946,9 @@ func prepareXgo() error { func runXgo(targets string) error { mg.Deps(initVars) - checkAndInstallGoTool("xgo", "src.techknowlogick.com/xgo") + if err := checkAndInstallGoTool("xgo", "src.techknowlogick.com/xgo"); err != nil { + return err + } extraLdflags := `-linkmode external -extldflags "-static" ` @@ -960,6 +972,9 @@ func runXgo(targets string) error { } if os.Getenv("DRONE_WORKSPACE") != "" { return filepath.Walk("/build/", func(path string, info os.FileInfo, err error) error { + if err != nil { + return err + } // Skip directories if info.IsDir() { return nil @@ -1018,7 +1033,10 @@ func (Release) Compress(ctx context.Context) error { errs, _ := errgroup.WithContext(ctx) - filepath.Walk("./"+DIST+"/binaries/", func(path string, info os.FileInfo, err error) error { + walkErr := filepath.Walk("./"+DIST+"/binaries/", func(path string, info os.FileInfo, err error) error { + if err != nil { + return err + } // Only executable files if !strings.Contains(info.Name(), Executable) { return nil @@ -1042,13 +1060,18 @@ func (Release) Compress(ctx context.Context) error { return nil }) - + if walkErr != nil { + return walkErr + } return errs.Wait() } // Copy copies all built binaries to dist/release/ in preparation for creating the os packages func (Release) Copy() error { return filepath.Walk("./"+DIST+"/binaries/", func(path string, info os.FileInfo, err error) error { + if err != nil { + return err + } // Only executable files if !strings.Contains(info.Name(), Executable) { return nil @@ -1096,6 +1119,9 @@ func (Release) OsPackage() error { // over the newly created files, creating some kind of endless loop. bins := make(map[string]os.FileInfo) if err := filepath.Walk(p, func(path string, info os.FileInfo, err error) error { + if err != nil { + return err + } if strings.Contains(info.Name(), ".sha256") || info.IsDir() { return nil } @@ -1147,7 +1173,7 @@ func (Release) Zip() error { fmt.Printf("Zipping %s...\n", info.Name()) zipFile := filepath.Join(rootDir, DIST, "zip", info.Name()+".zip") - c := exec.Command("zip", "-r", zipFile, ".", "-i", "*") + c := exec.Command("zip", "-r", zipFile, ".", "-i", "*") //nolint:gosec // This mage task creates zips of every directory recursively, it must use the directory name in the resulting file path to distinguish output files. c.Dir = path out, err := c.Output() fmt.Print(string(out)) @@ -1203,9 +1229,7 @@ func (Release) Packages() error { err = exec.Command(binpath).Run() } if err != nil && strings.Contains(err.Error(), "executable file not found") { - fmt.Println("Please manually install nfpm by running") - fmt.Println("curl -sfL https://install.goreleaser.com/github.com/goreleaser/nfpm.sh | sh -s -- -b $(go env GOPATH)/bin") - os.Exit(1) + return fmt.Errorf("executable %s not found: please manually install nfpm by running the command: curl -sfL https://install.goreleaser.com/github.com/goreleaser/nfpm.sh | sh -s -- -b $(go env GOPATH)/bin", binpath) } err = (Release{}).PrepareNFPMConfig() @@ -1371,7 +1395,7 @@ func (s *` + name + `) Handle(msg *message.Message) (err error) { } scanner := bufio.NewScanner(file) - var idx int64 = 0 + var idx int64 for scanner.Scan() { if scanner.Text() == "}" { // idx -= int64(len(scanner.Text())) @@ -1398,9 +1422,15 @@ func (s *` + name + `) Handle(msg *message.Message) (err error) { if err != nil { return err } - f.Seek(idx, 0) - f.Write([]byte(registerListenerCode)) - f.Write(remainder) + if _, err := f.Seek(idx, 0); err != nil { + return err + } + if _, err := f.Write([]byte(registerListenerCode)); err != nil { + return err + } + if _, err := f.Write(remainder); err != nil { + return err + } /////// // Append the listener code @@ -1438,7 +1468,7 @@ func (n *` + name + `) ToMail(lang string) *notifications.Mail { } // ToDB returns the ` + name + ` notification in a format which can be saved in the db -func (n *` + name + `) ToDB() interface{} { +func (n *` + name + `) ToDB() any { return nil } @@ -1466,13 +1496,15 @@ const DefaultConfigYAMLSamplePath = "config.yml.sample" func (Generate) SwaggerDocs() error { mg.Deps(initVars) - checkAndInstallGoTool("swag", "github.com/swaggo/swag/cmd/swag") + if err := checkAndInstallGoTool("swag", "github.com/swaggo/swag/cmd/swag"); err != nil { + return err + } return runAndStreamOutput("swag", "init", "-g", "./pkg/routes/routes.go", "--parseDependency", "-d", ".", "-o", "./pkg/swagger") } type ConfigNode struct { Key string `json:"key,omitempty"` - Value interface{} `json:"default_value,omitempty"` + Value any `json:"default_value,omitempty"` Comment string `json:"comment,omitempty"` Children []*ConfigNode `json:"children,omitempty"` } @@ -1523,14 +1555,15 @@ func convertConfigJSONToYAML(node *ConfigNode, indent int, isTopLevel bool, pare isProviders := node.Key == "providers" && parentKey == "openid" isArray := len(node.Children) > 0 && node.Children[0].Key == "" for i, child := range node.Children { - if isProviders { + switch { + case isProviders: writeComment(child.Comment, indent+1) writeLine("-", indent+1) result.WriteString(convertConfigJSONToYAML(child, indent+1, false, node.Key, commentOut)) - } else if isArray { + case isArray: writeComment(child.Comment, indent+1) writeLine("- "+formatValue(child.Value), indent+1) - } else { + default: result.WriteString(convertConfigJSONToYAML(child, indent+1, false, node.Key, commentOut)) } if i == len(node.Children)-1 && !isProviders && !isArray { @@ -1542,7 +1575,7 @@ func convertConfigJSONToYAML(node *ConfigNode, indent int, isTopLevel bool, pare return result.String() } -func formatValue(value interface{}) string { +func formatValue(value any) string { switch v := value.(type) { case string: if intValue, err := strconv.Atoi(v); err == nil { @@ -1584,7 +1617,7 @@ func generateConfigYAMLFromJSON(yamlPath string, commented bool) { yamlData := convertConfigJSONToYAML(&root, -1, true, "", commented) - err = os.WriteFile(yamlPath, []byte(yamlData), 0o644) + err = os.WriteFile(yamlPath, []byte(yamlData), 0o600) if err != nil { fmt.Println("Error writing YAML file:", err) return @@ -1640,7 +1673,7 @@ func (Dev) PrepareWorktree(name string, planPath string) error { re2 := regexp.MustCompile(`(?m)^(\s*rootpath:\s*)(/[^\s\n]+)`) newConfig = re2.ReplaceAllString(newConfig, `${1}"`+worktreePath+`"`) - if err := os.WriteFile(configDst, []byte(newConfig), 0o644); err != nil { + if err := os.WriteFile(configDst, []byte(newConfig), 0o600); err != nil { return fmt.Errorf("failed to write config.yml: %w", err) } printSuccess("Config copied with updated rootpath!") @@ -1724,7 +1757,7 @@ func (Dev) PrepareWorktree(name string, planPath string) error { // printReleaseStats prints commit statistics for the range between two refs. func printReleaseStats(fromRef, toRef string) error { - output, err := runCmdWithOutput("git", "log", fromRef+".."+toRef, "--oneline") + output, err := runGitCommandWithOutput("log", fromRef+".."+toRef, "--oneline") if err != nil { return fmt.Errorf("failed to get commit log: %w", err) } @@ -1791,7 +1824,7 @@ func (Dev) TagRelease(version string) error { fmt.Printf("Creating release %s...\n", version) // Get the last tag - lastTagBytes, err := runCmdWithOutput("git", "describe", "--tags", "--abbrev=0") + lastTagBytes, err := runGitCommandWithOutput("describe", "--tags", "--abbrev=0") if err != nil { return fmt.Errorf("failed to get last tag: %w", err) } @@ -1805,7 +1838,7 @@ func (Dev) TagRelease(version string) error { // Generate changelog using git cliff fmt.Println("Generating changelog...") - changelogBytes, err := runCmdWithOutput("git", "cliff", lastTag+"..HEAD", "--tag", version) + changelogBytes, err := runGitCommandWithOutput("cliff", lastTag+"..HEAD", "--tag", version) if err != nil { return fmt.Errorf("failed to generate changelog: %w", err) } @@ -1887,7 +1920,8 @@ func cleanupChangelog(changelog string) string { strings.HasPrefix(trimmedLine, "### ") || trimmedLine == "" - if isNewEntry { + switch { + case isNewEntry: // Flush the current entry if any if currentEntry.Len() > 0 { entryStr := strings.TrimSpace(currentEntry.String()) @@ -1899,22 +1933,23 @@ func cleanupChangelog(changelog string) string { } // Start a new entry or add empty line/header - if trimmedLine == "" { + switch { + case trimmedLine == "": // Only add empty line if the previous line wasn't empty if len(cleanedLines) > 0 && cleanedLines[len(cleanedLines)-1] != "" { cleanedLines = append(cleanedLines, "") } - } else if strings.HasPrefix(trimmedLine, "## ") || strings.HasPrefix(trimmedLine, "### ") { + case strings.HasPrefix(trimmedLine, "## ") || strings.HasPrefix(trimmedLine, "### "): // Headers are never duplicates cleanedLines = append(cleanedLines, trimmedLine) - } else { + default: currentEntry.WriteString(trimmedLine) } - } else if currentEntry.Len() > 0 { + case currentEntry.Len() > 0: // This is a continuation of the current entry currentEntry.WriteString(" ") currentEntry.WriteString(trimmedLine) - } else if trimmedLine != "" { + case trimmedLine != "": // Standalone line that's not part of an entry if !seenLines[trimmedLine] { cleanedLines = append(cleanedLines, trimmedLine) @@ -1949,7 +1984,7 @@ func updateReadmeBadge(version string) error { re := regexp.MustCompile(`(download-)(v[0-9a-zA-Z.]+)(-brightgreen)`) newContent := re.ReplaceAllString(string(content), "${1}"+badgeVersion+"${3}") - if err := os.WriteFile(readmePath, []byte(newContent), 0o644); err != nil { + if err := os.WriteFile(readmePath, []byte(newContent), 0o600); err != nil { return fmt.Errorf("failed to write README.md: %w", err) } @@ -1970,7 +2005,7 @@ func updateFrontendPackageJSON(version string) error { re := regexp.MustCompile(`("version"\s*:\s*")([^"]+)(")`) newContent := re.ReplaceAllString(string(content), "${1}"+npmVersion+"${3}") - if err := os.WriteFile(pkgPath, []byte(newContent), 0o644); err != nil { + if err := os.WriteFile(pkgPath, []byte(newContent), 0o600); err != nil { return fmt.Errorf("failed to write %s: %w", pkgPath, err) } @@ -2005,7 +2040,7 @@ func prependChangelog(newChangelog string) error { strings.TrimSpace(newChangelog) + "\n" + existingVersions - if err := os.WriteFile(changelogPath, []byte(newContent), 0o644); err != nil { + if err := os.WriteFile(changelogPath, []byte(newContent), 0o600); err != nil { return fmt.Errorf("failed to write CHANGELOG.md: %w", err) } @@ -2019,11 +2054,12 @@ func prepareTagMessage(changelog string) string { for _, line := range lines { // Remove ## and ### prefixes - if strings.HasPrefix(line, "### ") { + switch { + case strings.HasPrefix(line, "### "): result = append(result, strings.TrimPrefix(line, "### ")) - } else if strings.HasPrefix(line, "## ") { + case strings.HasPrefix(line, "## "): result = append(result, strings.TrimPrefix(line, "## ")) - } else { + default: result = append(result, line) } } @@ -2044,7 +2080,7 @@ func (Plugins) Build(pathToSourceFiles string) error { if !strings.HasPrefix(pathToSourceFiles, "/") { absPath, err := filepath.Abs(pathToSourceFiles) if err != nil { - return fmt.Errorf("failed to resolve absolute path: %v", err) + return fmt.Errorf("failed to resolve absolute path: %w", err) } pathToSourceFiles = absPath } From 0a1104b75ce1a6fcadb0cd0678400cf3585a0eb1 Mon Sep 17 00:00:00 2001 From: John Starich Date: Fri, 6 Mar 2026 01:12:23 -0600 Subject: [PATCH 028/142] refactor: fix contextcheck lint errors on magefile by passing mage context --- magefile.go | 222 +++++++++++++++++++++++++++------------------------- 1 file changed, 116 insertions(+), 106 deletions(-) diff --git a/magefile.go b/magefile.go index 45943bb13..e3aeda4bd 100644 --- a/magefile.go +++ b/magefile.go @@ -87,8 +87,8 @@ func goDetectVerboseFlag() string { return fmt.Sprintf("-v=%t", mg.Verbose()) } -func runGitCommandWithOutput(arg ...string) (output []byte, err error) { - cmd := exec.Command("git", arg...) +func runGitCommandWithOutput(ctx context.Context, arg ...string) (output []byte, err error) { + cmd := exec.CommandContext(ctx, "git", arg...) output, err = cmd.Output() if err != nil { var ee *exec.ExitError @@ -101,8 +101,8 @@ func runGitCommandWithOutput(arg ...string) (output []byte, err error) { return output, nil } -func getRawVersionString() (version string, err error) { - version, err = getRawVersionNumber() +func getRawVersionString(ctx context.Context) (version string, err error) { + version, err = getRawVersionNumber(ctx) if err != nil { return } @@ -118,7 +118,7 @@ func getRawVersionString() (version string, err error) { return } -func getRawVersionNumber() (version string, err error) { +func getRawVersionNumber(ctx context.Context) (version string, err error) { versionEnv := os.Getenv("RELEASE_VERSION") if versionEnv != "" { return versionEnv, nil @@ -132,19 +132,19 @@ func getRawVersionNumber() (version string, err error) { return strings.Replace(os.Getenv("DRONE_BRANCH"), "release/v", "", 1), nil } - versionBytes, err := runGitCommandWithOutput("describe", "--tags", "--always", "--abbrev=10") + versionBytes, err := runGitCommandWithOutput(ctx, "describe", "--tags", "--always", "--abbrev=10") return string(versionBytes), err } -func setVersion() error { - versionNumber, err := getRawVersionNumber() +func setVersion(ctx context.Context) error { + versionNumber, err := getRawVersionNumber(ctx) if err != nil { return err } VersionNumber = strings.Trim(versionNumber, "\n") VersionNumber = strings.Replace(VersionNumber, "-g", "-", 1) - version, err := getRawVersionString() + version, err := getRawVersionString(ctx) if err != nil { return fmt.Errorf("error getting version: %w", err) } @@ -178,13 +178,13 @@ func init() { } // Some variables have external dependencies (like git) which may not always be available. -func initVars() error { +func initVars(ctx context.Context) error { // Always include osusergo to use pure Go os/user implementation instead of CGO. // This prevents SIGFPE crashes when running under systemd without HOME set, // caused by glibc's getpwuid_r() failing in certain environments. // See: https://github.com/go-vikunja/vikunja/issues/2170 Tags = "osusergo " + strings.ReplaceAll(os.Getenv("TAGS"), ",", " ") - if err := setVersion(); err != nil { + if err := setVersion(ctx); err != nil { return err } setBinLocation() @@ -193,8 +193,8 @@ func initVars() error { return nil } -func runAndStreamOutput(cmd string, args ...string) error { - c := exec.Command(cmd, args...) +func runAndStreamOutput(ctx context.Context, cmd string, args ...string) error { + c := exec.CommandContext(ctx, cmd, args...) c.Env = os.Environ() c.Stdout = os.Stdout @@ -206,10 +206,10 @@ func runAndStreamOutput(cmd string, args ...string) error { // Will check if the tool exists and if not install it from the provided import path // If any errors occur, it will exit with a status code of 1. -func checkAndInstallGoTool(tool, importPath string) error { - if err := exec.Command(tool).Run(); err != nil && strings.Contains(err.Error(), "executable file not found") { +func checkAndInstallGoTool(ctx context.Context, tool, importPath string) error { + if err := exec.CommandContext(ctx, tool).Run(); err != nil && strings.Contains(err.Error(), "executable file not found") { fmt.Printf("%s not installed, installing %s...\n", tool, importPath) - if err := exec.Command("go", "install", goDetectVerboseFlag(), importPath).Run(); err != nil { //nolint:gosec // Every caller to checkAndInstallGoTool is hard-coded at time of writing, so no injection possible. + if err := exec.CommandContext(ctx, "go", "install", goDetectVerboseFlag(), importPath).Run(); err != nil { //nolint:gosec // Every caller to checkAndInstallGoTool is hard-coded at time of writing, so no injection possible. return fmt.Errorf("error installing %s: %w", tool, err) } fmt.Println("Installed.") @@ -324,16 +324,16 @@ func printSuccess(text string, args ...any) { } // getE2EPort returns the port from the given env var, or a random available port. -func getE2EPort(envVar string) (int, error) { +func getE2EPort(ctx context.Context, envVar string) (int, error) { if v := os.Getenv(envVar); v != "" { return strconv.Atoi(v) } - return getRandomPort() + return getRandomPort(ctx) } // getRandomPort finds a random available TCP port. -func getRandomPort() (int, error) { - l, err := net.Listen("tcp", "127.0.0.1:0") +func getRandomPort(ctx context.Context) (int, error) { + l, err := (&net.ListenConfig{}).Listen(ctx, "tcp", "127.0.0.1:0") if err != nil { return 0, err } @@ -362,11 +362,15 @@ func killProcessGroup(cmd *exec.Cmd) error { } // waitForHTTP polls a URL until it returns a 200 status or the timeout expires. -func waitForHTTP(url string, timeout time.Duration) error { +func waitForHTTP(ctx context.Context, url string, timeout time.Duration) error { deadline := time.Now().Add(timeout) client := &http.Client{Timeout: 2 * time.Second} for time.Now().Before(deadline) { - resp, err := client.Get(url) + req, err := http.NewRequestWithContext(ctx, http.MethodGet, url, nil) + if err != nil { + return err + } + resp, err := client.Do(req) if err == nil { resp.Body.Close() if resp.StatusCode == http.StatusOK { @@ -379,7 +383,7 @@ func waitForHTTP(url string, timeout time.Duration) error { } // Fmt formats the code using go fmt -func Fmt() error { +func Fmt(ctx context.Context) error { mg.Deps(initVars) var goFiles []string err := filepath.Walk(".", func(path string, info fs.FileInfo, err error) error { @@ -395,37 +399,37 @@ func Fmt() error { return err } args := append([]string{"-s", "-w"}, goFiles...) - return runAndStreamOutput("gofmt", args...) + return runAndStreamOutput(ctx, "gofmt", args...) } type Test mg.Namespace // Feature runs the feature tests -func (Test) Feature() error { +func (Test) Feature(ctx context.Context) error { mg.Deps(initVars) // We run everything sequentially and not in parallel to prevent issues with real test databases - return runAndStreamOutput("go", "test", goDetectVerboseFlag(), "-p", "1", "-coverprofile", "cover.out", "-timeout", "45m", "-short", "./...") + return runAndStreamOutput(ctx, "go", "test", goDetectVerboseFlag(), "-p", "1", "-coverprofile", "cover.out", "-timeout", "45m", "-short", "./...") } // Coverage runs the tests and builds the coverage html file from coverage output -func (Test) Coverage() error { +func (Test) Coverage(ctx context.Context) error { mg.Deps(initVars) mg.Deps(Test.Feature) - return runAndStreamOutput("go", "tool", "cover", "-html=cover.out", "-o", "cover.html") + return runAndStreamOutput(ctx, "go", "tool", "cover", "-html=cover.out", "-o", "cover.html") } // Web runs the web tests -func (Test) Web() error { +func (Test) Web(ctx context.Context) error { mg.Deps(initVars) // We run everything sequentially and not in parallel to prevent issues with real test databases args := []string{"test", goDetectVerboseFlag(), "-p", "1", "-timeout", "45m", "./pkg/webtests"} - return runAndStreamOutput("go", args...) + return runAndStreamOutput(ctx, "go", args...) } -func (Test) Filter(filter string) error { +func (Test) Filter(ctx context.Context, filter string) error { mg.Deps(initVars) // We run everything sequentially and not in parallel to prevent issues with real test databases - return runAndStreamOutput("go", "test", goDetectVerboseFlag(), "-p", "1", "-timeout", "45m", "-run", filter, "-short", "./...") + return runAndStreamOutput(ctx, "go", "test", goDetectVerboseFlag(), "-p", "1", "-timeout", "45m", "-run", filter, "-short", "./...") } func (Test) All() { @@ -436,9 +440,9 @@ func (Test) All() { // E2EApi runs the end-to-end API tests in pkg/e2etests. // These tests use the real event system (not events.Fake()) to verify // the full async pipeline: web handler → DB → event dispatch → watermill → listener. -func (Test) E2EApi() error { +func (Test) E2EApi(ctx context.Context) error { mg.Deps(initVars) - return runAndStreamOutput("go", "test", goDetectVerboseFlag(), "-p", "1", "-timeout", "45m", "./pkg/e2etests") + return runAndStreamOutput(ctx, "go", "test", goDetectVerboseFlag(), "-p", "1", "-timeout", "45m", "./pkg/e2etests") } // E2E builds the API, starts it with an in-memory database and the frontend dev server, @@ -458,15 +462,15 @@ func (Test) E2EApi() error { // - VIKUNJA_E2E_FRONTEND_PORT: Frontend port (default: random) // - VIKUNJA_E2E_TESTING_TOKEN: Testing token for seed endpoints (default: random) // - VIKUNJA_E2E_SKIP_BUILD: Set to "true" to skip rebuilding the API binary (default: false) -func (Test) E2E(args string) error { +func (Test) E2E(ctx context.Context, args string) error { mg.Deps(initVars) // Determine ports - apiPort, err := getE2EPort("VIKUNJA_E2E_API_PORT") + apiPort, err := getE2EPort(ctx, "VIKUNJA_E2E_API_PORT") if err != nil { return fmt.Errorf("could not get API port: %w", err) } - frontendPort, err := getE2EPort("VIKUNJA_E2E_FRONTEND_PORT") + frontendPort, err := getE2EPort(ctx, "VIKUNJA_E2E_FRONTEND_PORT") if err != nil { return fmt.Errorf("could not get frontend port: %w", err) } @@ -485,7 +489,7 @@ func (Test) E2E(args string) error { // Build the API binary (unless skipped) if os.Getenv("VIKUNJA_E2E_SKIP_BUILD") != "true" { fmt.Println("\n--- Building API binary ---") - if err := (Build{}).Build(); err != nil { + if err := (Build{}).Build(ctx); err != nil { return fmt.Errorf("failed to build API: %w", err) } } @@ -507,7 +511,7 @@ func (Test) E2E(args string) error { // Start the API server — all config via env vars, no config file // Uses in-memory SQLite (no DB file on disk) fmt.Println("\n--- Starting API server ---") - apiCmd := exec.Command("./vikunja", "web") + apiCmd := exec.CommandContext(ctx, "./vikunja", "web") apiCmd.Env = append(os.Environ(), fmt.Sprintf("VIKUNJA_SERVICE_INTERFACE=:%d", apiPort), fmt.Sprintf("VIKUNJA_SERVICE_PUBLICURL=http://127.0.0.1:%d/", apiPort), @@ -538,14 +542,14 @@ func (Test) E2E(args string) error { // Wait for API to be ready apiBase := fmt.Sprintf("http://127.0.0.1:%d/api/v1", apiPort) fmt.Printf("Waiting for API at %s ...\n", apiBase) - if err := waitForHTTP(apiBase+"/info", 30*time.Second); err != nil { + if err := waitForHTTP(ctx, apiBase+"/info", 30*time.Second); err != nil { return fmt.Errorf("API failed to start: %w", err) } printSuccess("API is ready!") // Build the frontend fmt.Println("\n--- Building frontend ---") - buildFrontendCmd := exec.Command("pnpm", "build:dev") + buildFrontendCmd := exec.CommandContext(ctx, "pnpm", "build:dev") buildFrontendCmd.Dir = "frontend" buildFrontendCmd.Stdout = os.Stdout buildFrontendCmd.Stderr = os.Stderr @@ -556,7 +560,7 @@ func (Test) E2E(args string) error { // Serve the built frontend with vite preview (static, no file watchers) fmt.Println("\n--- Starting frontend preview server ---") - frontendCmd := exec.Command("pnpm", "preview:dev", "--port", strconv.Itoa(frontendPort)) //nolint:gosec // This mage task runs end to end tests with environment-based configuration, it must use the port environment variable to suit its current environment. + frontendCmd := exec.CommandContext(ctx, "pnpm", "preview:dev", "--port", strconv.Itoa(frontendPort)) //nolint:gosec // This mage task runs end to end tests with environment-based configuration, it must use the port environment variable to suit its current environment. frontendCmd.Dir = "frontend" frontendCmd.Stdout = os.Stdout frontendCmd.Stderr = os.Stderr @@ -574,7 +578,7 @@ func (Test) E2E(args string) error { // Wait for frontend to be ready frontendBase := fmt.Sprintf("http://127.0.0.1:%d", frontendPort) fmt.Printf("Waiting for frontend at %s ...\n", frontendBase) - if err := waitForHTTP(frontendBase, 60*time.Second); err != nil { + if err := waitForHTTP(ctx, frontendBase, 60*time.Second); err != nil { return fmt.Errorf("frontend failed to start: %w", err) } printSuccess("Frontend is ready!") @@ -585,7 +589,7 @@ func (Test) E2E(args string) error { if strings.TrimSpace(args) != "" { playwrightArgs = append(playwrightArgs, strings.Fields(args)...) } - playwrightCmd := exec.Command("pnpm", playwrightArgs...) + playwrightCmd := exec.CommandContext(ctx, "pnpm", playwrightArgs...) playwrightCmd.Dir = "frontend" playwrightCmd.Env = append(os.Environ(), fmt.Sprintf("API_URL=%s/", apiBase), @@ -609,7 +613,7 @@ func (Test) E2E(args string) error { type Check mg.Namespace // GotSwag checks if the swagger docs need to be re-generated from the code annotations -func (Check) GotSwag() error { +func (Check) GotSwag(ctx context.Context) error { mg.Deps(initVars) // The check is pretty cheaply done: We take the hash of the swagger.json file, generate the docs, // hash the file again and compare the two hashes to see if anything changed. If that's the case, @@ -622,7 +626,7 @@ func (Check) GotSwag() error { return fmt.Errorf("error getting old hash of the swagger docs: %w", err) } - if generateErr := (Generate{}).SwaggerDocs(); generateErr != nil { + if generateErr := (Generate{}).SwaggerDocs(ctx); generateErr != nil { return generateErr } @@ -793,26 +797,26 @@ func extractTranslationKeysFromFile(filePath string) ([]TranslationKey, error) { return keys, nil } -func checkGolangCiLintInstalled() error { +func checkGolangCiLintInstalled(ctx context.Context) error { mg.Deps(initVars) - if err := exec.Command("golangci-lint").Run(); err != nil && strings.Contains(err.Error(), "executable file not found") { + if err := exec.CommandContext(ctx, "golangci-lint").Run(); err != nil && strings.Contains(err.Error(), "executable file not found") { return fmt.Errorf("golangci-lint executable failed to run, please manually install golangci-lint by running the command: curl -sSfL https://raw.githubusercontent.com/golangci/golangci-lint/master/install.sh | sh -s -- -b $(go env GOPATH)/bin v2.4.0") } return nil } -func (Check) Golangci() error { - if err := checkGolangCiLintInstalled(); err != nil { +func (Check) Golangci(ctx context.Context) error { + if err := checkGolangCiLintInstalled(ctx); err != nil { return err } - return runAndStreamOutput("golangci-lint", "run") + return runAndStreamOutput(ctx, "golangci-lint", "run") } -func (Check) GolangciFix() error { - if err := checkGolangCiLintInstalled(); err != nil { +func (Check) GolangciFix(ctx context.Context) error { + if err := checkGolangCiLintInstalled(ctx); err != nil { return err } - return runAndStreamOutput("golangci-lint", "run", "--fix") + return runAndStreamOutput(ctx, "golangci-lint", "run", "--fix") } // All runs golangci and the swagger test in parallel @@ -828,9 +832,9 @@ func (Check) All() { type Build mg.Namespace // Clean cleans all build, executable and bindata files -func (Build) Clean() error { +func (Build) Clean(ctx context.Context) error { mg.Deps(initVars) - if err := exec.Command("go", "clean", "./...").Run(); err != nil { + if err := exec.CommandContext(ctx, "go", "clean", "./...").Run(); err != nil { return err } if err := os.Remove(Executable); err != nil && !os.IsNotExist(err) { @@ -846,7 +850,7 @@ func (Build) Clean() error { } // Build builds a vikunja binary, ready to run -func (Build) Build() error { +func (Build) Build(ctx context.Context) error { mg.Deps(initVars) // Check if the frontend dist folder exists distPath := filepath.Join("frontend", "dist") @@ -866,7 +870,7 @@ func (Build) Build() error { fmt.Printf("Warning: %s not found, created empty file\n", indexFile) } - return runAndStreamOutput("go", "build", goDetectVerboseFlag(), "-tags", Tags, "-ldflags", "-s -w "+Ldflags, "-o", Executable) + return runAndStreamOutput(ctx, "go", "build", goDetectVerboseFlag(), "-tags", Tags, "-ldflags", "-s -w "+Ldflags, "-o", Executable) } func (Build) SaveVersionToFile() error { @@ -898,9 +902,9 @@ func (Release) Release(ctx context.Context) error { // Run compiling in parallel to speed it up errs, _ := errgroup.WithContext(ctx) - errs.Go((Release{}).Windows) - errs.Go((Release{}).Linux) - errs.Go((Release{}).Darwin) + errgroupGoWithContext(ctx, errs, (Release{}).Windows) + errgroupGoWithContext(ctx, errs, (Release{}).Linux) + errgroupGoWithContext(ctx, errs, (Release{}).Darwin) if err := errs.Wait(); err != nil { return err } @@ -917,13 +921,19 @@ func (Release) Release(ctx context.Context) error { if err := (Release{}).OsPackage(); err != nil { return err } - if err := (Release{}).Zip(); err != nil { + if err := (Release{}).Zip(ctx); err != nil { return err } return nil } +func errgroupGoWithContext(ctx context.Context, errs *errgroup.Group, do func(context.Context) error) { + errs.Go(func() error { + return do(ctx) + }) +} + // Dirs creates all directories needed to release vikunja func (Release) Dirs() error { for _, d := range []string{"binaries", "release", "zip"} { @@ -934,19 +944,19 @@ func (Release) Dirs() error { return nil } -func prepareXgo() error { +func prepareXgo(ctx context.Context) error { mg.Deps(initVars) - if err := checkAndInstallGoTool("xgo", "src.techknowlogick.com/xgo"); err != nil { + if err := checkAndInstallGoTool(ctx, "xgo", "src.techknowlogick.com/xgo"); err != nil { return err } fmt.Println("Pulling latest xgo docker image...") - return runAndStreamOutput("docker", "pull", "ghcr.io/techknowlogick/xgo:latest") + return runAndStreamOutput(ctx, "docker", "pull", "ghcr.io/techknowlogick/xgo:latest") } -func runXgo(targets string) error { +func runXgo(ctx context.Context, targets string) error { mg.Deps(initVars) - if err := checkAndInstallGoTool("xgo", "src.techknowlogick.com/xgo"); err != nil { + if err := checkAndInstallGoTool(ctx, "xgo", "src.techknowlogick.com/xgo"); err != nil { return err } @@ -961,7 +971,7 @@ func runXgo(targets string) error { outName = Executable + "-" + Version } - if err := runAndStreamOutput("xgo", + if err := runAndStreamOutput(ctx, "xgo", "-dest", "./"+DIST+"/binaries", "-tags", "netgo "+Tags, "-ldflags", extraLdflags+Ldflags, @@ -987,12 +997,12 @@ func runXgo(targets string) error { } // Windows builds binaries for windows -func (Release) Windows() error { - return runXgo("windows/*") +func (Release) Windows(ctx context.Context) error { + return runXgo(ctx, "windows/*") } // Linux builds binaries for linux -func (Release) Linux() error { +func (Release) Linux(ctx context.Context) error { targets := []string{ "linux/amd64", "linux/arm-5", @@ -1005,15 +1015,15 @@ func (Release) Linux() error { "linux/mips64le", "linux/riscv64", } - return runXgo(strings.Join(targets, ",")) + return runXgo(ctx, strings.Join(targets, ",")) } // Darwin builds binaries for darwin -func (Release) Darwin() error { - return runXgo("darwin-10.15/*") +func (Release) Darwin(ctx context.Context) error { + return runXgo(ctx, "darwin-10.15/*") } -func (Release) Xgo(target string) error { +func (Release) Xgo(ctx context.Context, target string) error { parts := strings.Split(target, "/") if len(parts) < 2 { return fmt.Errorf("invalid target") @@ -1024,7 +1034,7 @@ func (Release) Xgo(target string) error { variant = "-" + strings.ReplaceAll(parts[2], "v", "") } - return runXgo(parts[0] + "/" + parts[1] + variant) + return runXgo(ctx, parts[0]+"/"+parts[1]+variant) } // Compress compresses the built binaries in dist/binaries/ to reduce their filesize @@ -1052,10 +1062,10 @@ func (Release) Compress(ctx context.Context) error { // Runs compressing in parallel since upx is single-threaded errs.Go(func() error { - if err := runAndStreamOutput("chmod", "+x", path); err != nil { // Make sure all binaries are executable. Sometimes the CI does weird things and they're not. + if err := runAndStreamOutput(ctx, "chmod", "+x", path); err != nil { // Make sure all binaries are executable. Sometimes the CI does weird things and they're not. return err } - return runAndStreamOutput("upx", "-9", path) + return runAndStreamOutput(ctx, "upx", "-9", path) }) return nil @@ -1155,7 +1165,7 @@ func (Release) OsPackage() error { } // Zip creates a zip file from all os-package folders in dist/release -func (Release) Zip() error { +func (Release) Zip(ctx context.Context) error { rootDir, err := os.Getwd() if err != nil { return fmt.Errorf("could not get working directory: %w", err) @@ -1173,7 +1183,7 @@ func (Release) Zip() error { fmt.Printf("Zipping %s...\n", info.Name()) zipFile := filepath.Join(rootDir, DIST, "zip", info.Name()+".zip") - c := exec.Command("zip", "-r", zipFile, ".", "-i", "*") //nolint:gosec // This mage task creates zips of every directory recursively, it must use the directory name in the resulting file path to distinguish output files. + c := exec.CommandContext(ctx, "zip", "-r", zipFile, ".", "-i", "*") //nolint:gosec // This mage task creates zips of every directory recursively, it must use the directory name in the resulting file path to distinguish output files. c.Dir = path out, err := c.Output() fmt.Print(string(out)) @@ -1186,9 +1196,9 @@ func (Release) Zip() error { } // Reprepro creates a debian repo structure -func (Release) Reprepro() error { +func (Release) Reprepro(ctx context.Context) error { mg.Deps(setVersion, setBinLocation) - return runAndStreamOutput("reprepro_expect", "debian", "includedeb", "buster", "./"+DIST+"/os-packages/"+Executable+"_"+strings.ReplaceAll(VersionNumber, "v0", "0")+"_amd64.deb") + return runAndStreamOutput(ctx, "reprepro_expect", "debian", "includedeb", "buster", "./"+DIST+"/os-packages/"+Executable+"_"+strings.ReplaceAll(VersionNumber, "v0", "0")+"_amd64.deb") } // PrepareNFPMConfig prepares the nfpm config @@ -1215,7 +1225,7 @@ func (Release) PrepareNFPMConfig() error { } // Packages creates deb, rpm and apk packages -func (Release) Packages() error { +func (Release) Packages(ctx context.Context) error { mg.Deps(initVars) var err error @@ -1223,10 +1233,10 @@ func (Release) Packages() error { if binpath == "" { binpath = "nfpm" } - err = exec.Command(binpath).Run() + err = exec.CommandContext(ctx, binpath).Run() if err != nil && strings.Contains(err.Error(), "executable file not found") { binpath = "/usr/bin/nfpm" - err = exec.Command(binpath).Run() + err = exec.CommandContext(ctx, binpath).Run() } if err != nil && strings.Contains(err.Error(), "executable file not found") { return fmt.Errorf("executable %s not found: please manually install nfpm by running the command: curl -sfL https://install.goreleaser.com/github.com/goreleaser/nfpm.sh | sh -s -- -b $(go env GOPATH)/bin", binpath) @@ -1242,13 +1252,13 @@ func (Release) Packages() error { return err } - if err := runAndStreamOutput(binpath, "pkg", "--packager", "deb", "--target", releasePath); err != nil { + if err := runAndStreamOutput(ctx, binpath, "pkg", "--packager", "deb", "--target", releasePath); err != nil { return err } - if err := runAndStreamOutput(binpath, "pkg", "--packager", "rpm", "--target", releasePath); err != nil { + if err := runAndStreamOutput(ctx, binpath, "pkg", "--packager", "rpm", "--target", releasePath); err != nil { return err } - if err := runAndStreamOutput(binpath, "pkg", "--packager", "apk", "--target", releasePath); err != nil { + if err := runAndStreamOutput(ctx, binpath, "pkg", "--packager", "apk", "--target", releasePath); err != nil { return err } @@ -1493,13 +1503,13 @@ type Generate mg.Namespace const DefaultConfigYAMLSamplePath = "config.yml.sample" // SwaggerDocs generates the swagger docs from the code annotations -func (Generate) SwaggerDocs() error { +func (Generate) SwaggerDocs(ctx context.Context) error { mg.Deps(initVars) - if err := checkAndInstallGoTool("swag", "github.com/swaggo/swag/cmd/swag"); err != nil { + if err := checkAndInstallGoTool(ctx, "swag", "github.com/swaggo/swag/cmd/swag"); err != nil { return err } - return runAndStreamOutput("swag", "init", "-g", "./pkg/routes/routes.go", "--parseDependency", "-d", ".", "-o", "./pkg/swagger") + return runAndStreamOutput(ctx, "swag", "init", "-g", "./pkg/routes/routes.go", "--parseDependency", "-d", ".", "-o", "./pkg/swagger") } type ConfigNode struct { @@ -1636,7 +1646,7 @@ func (Generate) ConfigYAML(commented bool) { // The second argument is a path to a plan file that will be copied to the new worktree (pass "" to skip). // The worktree is created in the parent directory (../). // It also copies the current config.yml with an updated rootpath, and initializes the frontend. -func (Dev) PrepareWorktree(name string, planPath string) error { +func (Dev) PrepareWorktree(ctx context.Context, name string, planPath string) error { if name == "" { return fmt.Errorf("name is required: mage dev:prepare-worktree ") } @@ -1647,7 +1657,7 @@ func (Dev) PrepareWorktree(name string, planPath string) error { fmt.Printf("Creating worktree at %s with branch %s...\n", worktreePath, name) // Create the git worktree - cmd := exec.Command("git", "worktree", "add", worktreePath, "-b", name) + cmd := exec.CommandContext(ctx, "git", "worktree", "add", worktreePath, "-b", name) cmd.Stdout = os.Stdout cmd.Stderr = os.Stderr if err := cmd.Run(); err != nil { @@ -1728,7 +1738,7 @@ func (Dev) PrepareWorktree(name string, planPath string) error { frontendDir := filepath.Join(worktreePath, "frontend") // Run pnpm install - pnpmCmd := exec.Command("pnpm", "i") + pnpmCmd := exec.CommandContext(ctx, "pnpm", "i") pnpmCmd.Dir = frontendDir pnpmCmd.Stdout = os.Stdout pnpmCmd.Stderr = os.Stderr @@ -1737,7 +1747,7 @@ func (Dev) PrepareWorktree(name string, planPath string) error { } // Run patch-sass-embedded (shell alias from devenv) - patchCmd := exec.Command("bash", "-ic", "patch-sass-embedded") + patchCmd := exec.CommandContext(ctx, "bash", "-ic", "patch-sass-embedded") patchCmd.Dir = frontendDir patchCmd.Stdout = os.Stdout patchCmd.Stderr = os.Stderr @@ -1756,8 +1766,8 @@ func (Dev) PrepareWorktree(name string, planPath string) error { } // printReleaseStats prints commit statistics for the range between two refs. -func printReleaseStats(fromRef, toRef string) error { - output, err := runGitCommandWithOutput("log", fromRef+".."+toRef, "--oneline") +func printReleaseStats(ctx context.Context, fromRef, toRef string) error { + output, err := runGitCommandWithOutput(ctx, "log", fromRef+".."+toRef, "--oneline") if err != nil { return fmt.Errorf("failed to get commit log: %w", err) } @@ -1811,7 +1821,7 @@ func printReleaseStats(fromRef, toRef string) error { // TagRelease creates a new release tag with changelog. // It updates the version badge in README.md, generates changelog using git-cliff, // commits the changes, and creates an annotated tag. -func (Dev) TagRelease(version string) error { +func (Dev) TagRelease(ctx context.Context, version string) error { if version == "" { return fmt.Errorf("version is required: mage dev:tag-release ") } @@ -1824,7 +1834,7 @@ func (Dev) TagRelease(version string) error { fmt.Printf("Creating release %s...\n", version) // Get the last tag - lastTagBytes, err := runGitCommandWithOutput("describe", "--tags", "--abbrev=0") + lastTagBytes, err := runGitCommandWithOutput(ctx, "describe", "--tags", "--abbrev=0") if err != nil { return fmt.Errorf("failed to get last tag: %w", err) } @@ -1832,13 +1842,13 @@ func (Dev) TagRelease(version string) error { fmt.Printf("Last tag: %s\n", lastTag) // Print commit statistics - if err := printReleaseStats(lastTag, "HEAD"); err != nil { + if err := printReleaseStats(ctx, lastTag, "HEAD"); err != nil { fmt.Printf("Warning: could not print release stats: %v\n", err) } // Generate changelog using git cliff fmt.Println("Generating changelog...") - changelogBytes, err := runGitCommandWithOutput("cliff", lastTag+"..HEAD", "--tag", version) + changelogBytes, err := runGitCommandWithOutput(ctx, "cliff", lastTag+"..HEAD", "--tag", version) if err != nil { return fmt.Errorf("failed to generate changelog: %w", err) } @@ -1868,12 +1878,12 @@ func (Dev) TagRelease(version string) error { // Commit the changes fmt.Println("Committing changes...") commitMsg := fmt.Sprintf("chore: %s release preparations", version) - cmd := exec.Command("git", "add", "README.md", "CHANGELOG.md", "frontend/package.json") + cmd := exec.CommandContext(ctx, "git", "add", "README.md", "CHANGELOG.md", "frontend/package.json") if err := cmd.Run(); err != nil { return fmt.Errorf("failed to stage files: %w", err) } - cmd = exec.Command("git", "commit", "-m", commitMsg) + cmd = exec.CommandContext(ctx, "git", "commit", "-m", commitMsg) cmd.Stdout = os.Stdout cmd.Stderr = os.Stderr if err := cmd.Run(); err != nil { @@ -1885,7 +1895,7 @@ func (Dev) TagRelease(version string) error { // Create the annotated tag fmt.Printf("Creating tag %s...\n", version) - cmd = exec.Command("git", "tag", "-a", version, "-m", tagMessage) + cmd = exec.CommandContext(ctx, "git", "tag", "-a", version, "-m", tagMessage) cmd.Stdout = os.Stdout cmd.Stderr = os.Stderr if err := cmd.Run(); err != nil { @@ -2070,7 +2080,7 @@ func prepareTagMessage(changelog string) string { type Plugins mg.Namespace // Build compiles a Go plugin at the provided path. -func (Plugins) Build(pathToSourceFiles string) error { +func (Plugins) Build(ctx context.Context, pathToSourceFiles string) error { mg.Deps(initVars) if pathToSourceFiles == "" { return fmt.Errorf("please provide a plugin path") @@ -2086,5 +2096,5 @@ func (Plugins) Build(pathToSourceFiles string) error { } out := filepath.Join("plugins", filepath.Base(pathToSourceFiles)+".so") - return runAndStreamOutput("go", "build", "-buildmode=plugin", "-tags", Tags, "-o", out, pathToSourceFiles) + return runAndStreamOutput(ctx, "go", "build", "-buildmode=plugin", "-tags", Tags, "-o", out, pathToSourceFiles) } From 1b5f3f4ccd15a954d1b3ac4fa49a99c2f299deff Mon Sep 17 00:00:00 2001 From: John Starich Date: Fri, 6 Mar 2026 01:33:19 -0600 Subject: [PATCH 029/142] refactor: merge last unique build tag "tools" into go.mod tools section --- go.mod | 39 +++++++++-- go.sum | 204 +++++++++++++++++++++++++++++++++++++++++++++++++++++++ tools.go | 29 -------- 3 files changed, 236 insertions(+), 36 deletions(-) delete mode 100644 tools.go diff --git a/go.mod b/go.mod index d4086a04a..83facc58e 100644 --- a/go.mod +++ b/go.mod @@ -16,6 +16,8 @@ module code.vikunja.io/api +go 1.25.7 + require ( dario.cat/mergo v1.0.2 github.com/ThreeDotsLabs/watermill v1.5.1 @@ -78,12 +80,12 @@ require ( golang.org/x/net v0.49.0 golang.org/x/oauth2 v0.34.0 golang.org/x/sync v0.19.0 - golang.org/x/sys v0.40.0 - golang.org/x/term v0.39.0 + golang.org/x/sys v0.41.0 + golang.org/x/term v0.40.0 golang.org/x/text v0.33.0 gopkg.in/d4l3k/messagediff.v1 v1.2.1 mvdan.cc/xurls/v2 v2.6.0 - src.techknowlogick.com/xgo v1.8.1-0.20241105013731-313dedef864f + src.techknowlogick.com/xgo v1.9.0 src.techknowlogick.com/xormigrate v1.7.1 xorm.io/builder v0.3.13 xorm.io/xorm v1.3.11 @@ -91,8 +93,10 @@ require ( require ( filippo.io/edwards25519 v1.1.1 // indirect + github.com/Azure/go-ansiterm v0.0.0-20250102033503-faa5f7b0171c // indirect github.com/Azure/go-ntlmssp v0.0.0-20221128193559-754e69321358 // indirect github.com/KyleBanks/depth v1.2.1 // indirect + github.com/Microsoft/go-winio v0.6.2 // indirect github.com/aws/aws-sdk-go-v2/aws/protocol/eventstream v1.7.5 // indirect github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.18.18 // indirect github.com/aws/aws-sdk-go-v2/feature/s3/manager v1.22.4 // indirect @@ -118,13 +122,21 @@ require ( github.com/clipperhouse/displaywidth v0.6.2 // indirect github.com/clipperhouse/stringish v0.1.1 // indirect github.com/clipperhouse/uax29/v2 v2.3.0 // indirect + github.com/containerd/errdefs v1.0.0 // indirect + github.com/containerd/errdefs/pkg v0.3.0 // indirect github.com/cpuguy83/go-md2man/v2 v2.0.6 // indirect github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc // indirect github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f // indirect + github.com/distribution/reference v0.6.0 // indirect + github.com/docker/go-connections v0.6.0 // indirect + github.com/docker/go-units v0.5.0 // indirect + github.com/felixge/httpsnoop v1.0.4 // indirect github.com/fsnotify/fsnotify v1.9.0 // indirect github.com/go-asn1-ber/asn1-ber v1.5.8-0.20250403174932-29230038a667 // indirect github.com/go-chi/chi/v5 v5.2.2 // indirect github.com/go-jose/go-jose/v4 v4.1.3 // indirect + github.com/go-logr/logr v1.4.3 // indirect + github.com/go-logr/stdr v1.2.2 // indirect github.com/go-openapi/jsonpointer v0.21.0 // indirect github.com/go-openapi/jsonreference v0.20.3 // indirect github.com/go-openapi/spec v0.20.4 // indirect @@ -144,6 +156,10 @@ require ( github.com/mattn/go-isatty v0.0.20 // indirect github.com/mattn/go-runewidth v0.0.19 // indirect github.com/mitchellh/colorstring v0.0.0-20190213212951-d06e56a500db // indirect + github.com/moby/docker-image-spec v1.3.1 // indirect + github.com/moby/moby/api v1.53.0 // indirect + github.com/moby/moby/client v0.2.2 // indirect + github.com/moby/term v0.5.2 // indirect github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 // indirect github.com/oklog/ulid v1.3.1 // indirect github.com/olekukonko/cat v0.0.0-20250911104152-50322a0618f6 // indirect @@ -151,6 +167,8 @@ require ( github.com/olekukonko/ll v0.1.4-0.20260115111900-9e59c2286df0 // indirect github.com/onsi/ginkgo v1.16.4 // indirect github.com/onsi/gomega v1.16.0 // indirect + github.com/opencontainers/go-digest v1.0.0 // indirect + github.com/opencontainers/image-spec v1.1.1 // indirect github.com/pelletier/go-toml/v2 v2.2.4 // indirect github.com/pkg/errors v0.9.1 // indirect github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 // indirect @@ -169,6 +187,11 @@ require ( github.com/tj/assert v0.0.3 // indirect github.com/urfave/cli/v2 v2.3.0 // indirect github.com/yosssi/gohtml v0.0.0-20201013000340-ee4748c638f4 // indirect + go.opentelemetry.io/auto/sdk v1.2.1 // indirect + go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.65.0 // indirect + go.opentelemetry.io/otel v1.40.0 // indirect + go.opentelemetry.io/otel/metric v1.40.0 // indirect + go.opentelemetry.io/otel/trace v1.40.0 // indirect go.yaml.in/yaml/v2 v2.4.2 // indirect go.yaml.in/yaml/v3 v3.0.4 // indirect golang.org/x/mod v0.31.0 // indirect @@ -180,10 +203,12 @@ require ( sigs.k8s.io/yaml v1.3.0 // indirect ) +tool ( + github.com/magefile/mage + github.com/swaggo/swag/cmd/swag + src.techknowlogick.com/xgo +) + replace github.com/samedi/caldav-go => github.com/kolaente/caldav-go v3.0.1-0.20190610114120-2a4eb8b5dcc9+incompatible // Branch: feature/dynamic-supported-components, PR: https://github.com/samedi/caldav-go/pull/6 and https://github.com/samedi/caldav-go/pull/7 -go 1.25.0 - -toolchain go1.25.6 - replace github.com/fclairamb/afero-s3 => github.com/maggch97/afero-s3 v0.0.0-20260227031452-4db589f0d189 diff --git a/go.sum b/go.sum index a8ddafe99..ed39c6ced 100644 --- a/go.sum +++ b/go.sum @@ -1,27 +1,47 @@ +cloud.google.com/go/compute/metadata v0.3.0 h1:Tz+eQXMEqDIKRsmY3cHTL6FVaynIjX2QxYC4trgAKZc= +cloud.google.com/go/compute/metadata v0.3.0/go.mod h1:zFmK7XCadkQkj6TtorcaGlCW1hT1fIilQDwofLpJ20k= dario.cat/mergo v1.0.2 h1:85+piFYR1tMbRrLcDwR18y4UKJ3aH1Tbzi24VRW1TK8= dario.cat/mergo v1.0.2/go.mod h1:E/hbnu0NxMFBjpMIE34DRGLWqDy0g5FuKDhCb31ngxA= filippo.io/edwards25519 v1.1.1 h1:YpjwWWlNmGIDyXOn8zLzqiD+9TyIlPhGFG96P39uBpw= filippo.io/edwards25519 v1.1.1/go.mod h1:BxyFTGdWcka3PhytdK4V28tE5sGfRvvvRV7EaN4VDT4= gitea.com/xorm/sqlfiddle v0.0.0-20180821085327-62ce714f951a h1:lSA0F4e9A2NcQSqGqTOXqu2aRi/XEQxDCBwM8yJtE6s= gitea.com/xorm/sqlfiddle v0.0.0-20180821085327-62ce714f951a/go.mod h1:EXuID2Zs0pAQhH8yz+DNjUbjppKQzKFAn28TMYPB6IU= +gitee.com/travelliu/dm v1.8.11192 h1:aqJT0xhodZjRutIfEXxKYv0CxqmHUHzsbz6SFaRL6OY= gitee.com/travelliu/dm v1.8.11192/go.mod h1:DHTzyhCrM843x9VdKVbZ+GKXGRbKM2sJ4LxihRxShkE= +github.com/Azure/azure-sdk-for-go/sdk/azcore v0.19.0 h1:lhSJz9RMbJcTgxifR1hUNJnn6CNYtbgEDtQV22/9RBA= github.com/Azure/azure-sdk-for-go/sdk/azcore v0.19.0/go.mod h1:h6H6c8enJmmocHUbLiiGY6sx7f9i+X3m1CHdd5c6Rdw= +github.com/Azure/azure-sdk-for-go/sdk/azidentity v0.11.0 h1:OYa9vmRX2XC5GXRAzeggG12sF/z5D9Ahtdm9EJ00WN4= github.com/Azure/azure-sdk-for-go/sdk/azidentity v0.11.0/go.mod h1:HcM1YX14R7CJcghJGOYCgdezslRSVzqwLf/q+4Y2r/0= +github.com/Azure/azure-sdk-for-go/sdk/internal v0.7.0 h1:v9p9TfTbf7AwNb5NYQt7hI41IfPoLFiFkLtb+bmGjT0= github.com/Azure/azure-sdk-for-go/sdk/internal v0.7.0/go.mod h1:yqy467j36fJxcRV2TzfVZ1pCb5vxm4BtZPUdYWe/Xo8= +github.com/Azure/go-ansiterm v0.0.0-20250102033503-faa5f7b0171c h1:udKWzYgxTojEKWjV8V+WSxDXJ4NFATAsZjh8iIbsQIg= +github.com/Azure/go-ansiterm v0.0.0-20250102033503-faa5f7b0171c/go.mod h1:xomTg63KZ2rFqZQzSB4Vz2SUXa1BpHTVz9L5PTmPC4E= github.com/Azure/go-ntlmssp v0.0.0-20221128193559-754e69321358 h1:mFRzDkZVAjdal+s7s0MwaRv9igoPqLRdzOLzw/8Xvq8= github.com/Azure/go-ntlmssp v0.0.0-20221128193559-754e69321358/go.mod h1:chxPXzSsl7ZWRAuOIE23GDNzjWuZquvFlgA8xmpunjU= +github.com/BurntSushi/toml v0.3.1 h1:WXkYYl6Yr3qBf1K79EBnL4mak0OimBfB0XUf9Vl28OQ= github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= github.com/KyleBanks/depth v1.2.1 h1:5h8fQADFrWtarTdtDudMmGsC7GPbOAu6RVB3ffsVFHc= github.com/KyleBanks/depth v1.2.1/go.mod h1:jzSb9d0L43HxTQfT+oSA1EEp2q+ne2uh6XgeJcm8brE= +github.com/Masterminds/semver/v3 v3.1.1 h1:hLg3sBzpNErnxhQtUy/mmLR2I9foDujNK030IGemrRc= github.com/Masterminds/semver/v3 v3.1.1/go.mod h1:VPu/7SZ7ePZ3QOrcuXROw5FAcLl4a0cBrbBpGY/8hQs= +github.com/Microsoft/go-winio v0.6.2 h1:F2VQgta7ecxGYO8k3ZZz3RS8fVIXVxONVUPlNERoyfY= +github.com/Microsoft/go-winio v0.6.2/go.mod h1:yd8OoFMLzJbo9gZq8j5qaps8bJ9aShtEA8Ipt1oGCvU= +github.com/PuerkitoBio/purell v1.1.1 h1:WEQqlqaGbrPkxLJWfBwQmfEAE1Z7ONdDLqrN38tNFfI= github.com/PuerkitoBio/purell v1.1.1/go.mod h1:c11w/QuzBsJSee3cPx9rAFu61PvFxuPbtSwDGJws/X0= +github.com/PuerkitoBio/urlesc v0.0.0-20170810143723-de5bf2ad4578 h1:d+Bc7a5rLufV/sSk/8dngufqelfh6jnri85riMAaF/M= github.com/PuerkitoBio/urlesc v0.0.0-20170810143723-de5bf2ad4578/go.mod h1:uGdkoq3SwY9Y+13GIhn11/XLaGBb4BfwItxLd5jeuXE= github.com/ThreeDotsLabs/watermill v1.5.1 h1:t5xMivyf9tpmU3iozPqyrCZXHvoV1XQDfihas4sV0fY= github.com/ThreeDotsLabs/watermill v1.5.1/go.mod h1:Uop10dA3VeJWsSvis9qO3vbVY892LARrKAdki6WtXS4= github.com/adlio/trello v1.12.0 h1:JqOE2GFHQ9YtEviRRRSnicSxPbt4WFOxhqXzjMOw8lw= github.com/adlio/trello v1.12.0/go.mod h1:I4Lti4jf2KxjTNgTqs5W3lLuE78QZZdYbbPnQQGwjOo= +github.com/alecthomas/kingpin/v2 v2.4.0 h1:f48lwail6p8zpO1bC4TxtqACaGqHYA22qkHjHpqDjYY= +github.com/alecthomas/kingpin/v2 v2.4.0/go.mod h1:0gyi0zQnjuFk8xrkNKamJoyUo382HRL7ATRpFZCw6tE= +github.com/alecthomas/units v0.0.0-20211218093645-b94a6e3cc137 h1:s6gZFSlWYmbqAuRjVTiNNhvNRfY2Wxp9nhfyel4rklc= +github.com/alecthomas/units v0.0.0-20211218093645-b94a6e3cc137/go.mod h1:OMCwj8VM1Kc9e19TLln2VL61YJF0x1XFtfdL4JdbSyE= github.com/alexbrainman/sspi v0.0.0-20250919150558-7d374ff0d59e h1:4dAU9FXIyQktpoUAgOJK3OTFc/xug0PCXYCqU0FgDKI= github.com/alexbrainman/sspi v0.0.0-20250919150558-7d374ff0d59e/go.mod h1:cEWa1LVoE5KvSD9ONXsZrj0z6KqySlCCNKHlLzbqAt4= +github.com/andybalholm/brotli v1.0.5 h1:8uQZIdzKmjc/iuPu7O2ioW48L81FgatrcpfFmiq/cCs= +github.com/andybalholm/brotli v1.0.5/go.mod h1:fO7iG3H7G2nSZ7m0zPUDn85XEX2GTukHGRSepvi9Eig= github.com/arran4/golang-ical v0.3.2 h1:MGNjcXJFSuCXmYX/RpZhR2HDCYoFuK8vTPFLEdFC3JY= github.com/arran4/golang-ical v0.3.2/go.mod h1:xblDGxxIUMWwFZk9dlECUlc1iXNV65LJZOTHLVwu8bo= github.com/asaskevich/govalidator v0.0.0-20230301143203-a9d515a09cc2 h1:DklsrG3dyBCFEj5IhUbnKptjxatkF07cF2ak3yi77so= @@ -81,6 +101,8 @@ github.com/bsm/ginkgo/v2 v2.12.0 h1:Ny8MWAHyOepLGlLKYmXG4IEkioBysk6GpaRTLC8zwWs= github.com/bsm/ginkgo/v2 v2.12.0/go.mod h1:SwYbGRRDovPVboqFv0tPTcG1sN61LM1Z4ARdbAV9g4c= github.com/bsm/gomega v1.27.10 h1:yeMWxP2pV2fG3FgAODIY8EiRE3dy0aeFYt4l7wh6yKA= github.com/bsm/gomega v1.27.10/go.mod h1:JyEr/xRbxbtgWNi8tIEVPUYZ5Dzef52k01W3YH0H+O0= +github.com/bytedance/sonic v1.8.0 h1:ea0Xadu+sHlu7x5O3gKhRpQ1IKiMrSiHttPF0ybECuA= +github.com/bytedance/sonic v1.8.0/go.mod h1:i736AoUSYt75HyZLoJW9ERYxcy6eaN6h4BZXU064P/U= github.com/c2h5oh/datasize v0.0.0-20231215233829-aa82cc1e6500 h1:6lhrsTEnloDPXyeZBvSYvQf8u86jbKehZPVDDlkgDl4= github.com/c2h5oh/datasize v0.0.0-20231215233829-aa82cc1e6500/go.mod h1:S/7n9copUssQ56c7aAgHqftWO4LTf4xY6CGWt8Bc+3M= github.com/cenkalti/backoff/v5 v5.0.3 h1:ZN+IMa753KfX5hd8vVaMixjnqRZ3y8CuJKRKj1xcsSM= @@ -89,8 +111,13 @@ github.com/cespare/xxhash/v2 v2.3.0 h1:UL815xU9SqsFlibzuggzjXhog7bL6oX9BbNZnL2UF github.com/cespare/xxhash/v2 v2.3.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= github.com/chengxilo/virtualterm v1.0.4 h1:Z6IpERbRVlfB8WkOmtbHiDbBANU7cimRIof7mk9/PwM= github.com/chengxilo/virtualterm v1.0.4/go.mod h1:DyxxBZz/x1iqJjFxTFcr6/x+jSpqN0iwWCOK1q10rlY= +github.com/chenzhuoyu/base64x v0.0.0-20221115062448-fe3a3abad311 h1:qSGYFH7+jGhDF8vLC+iwCD4WpbV1EBDSzWkJODFLams= +github.com/chenzhuoyu/base64x v0.0.0-20221115062448-fe3a3abad311/go.mod h1:b583jCggY9gE99b6G5LEC39OIiVsWj+R97kbl5odCEk= +github.com/chzyer/logex v1.2.0 h1:+eqR0HfOetur4tgnC8ftU5imRnhi4te+BadWS95c5AM= github.com/chzyer/logex v1.2.0/go.mod h1:9+9sk7u7pGNWYMkh0hdiL++6OeibzJccyQU4p4MedaY= +github.com/chzyer/readline v1.5.0 h1:lSwwFrbNviGePhkewF1az4oLmcwqCZijQ2/Wi3BGHAI= github.com/chzyer/readline v1.5.0/go.mod h1:x22KAscuvRqlLoK9CsoYsmxoXZMMFVyOl86cAH8qUic= +github.com/chzyer/test v0.0.0-20210722231415-061457976a23 h1:dZ0/VyGgQdVGAss6Ju0dt5P0QltE0SFY5Woh6hbIfiQ= github.com/chzyer/test v0.0.0-20210722231415-061457976a23/go.mod h1:Q3SI9o4m/ZMnBNeIyt5eFwwo7qiLfzFZmjNmxjkiQlU= github.com/clipperhouse/displaywidth v0.6.2 h1:ZDpTkFfpHOKte4RG5O/BOyf3ysnvFswpyYrV7z2uAKo= github.com/clipperhouse/displaywidth v0.6.2/go.mod h1:R+kHuzaYWFkTm7xoMmK1lFydbci4X2CicfbGstSGg0o= @@ -98,16 +125,26 @@ github.com/clipperhouse/stringish v0.1.1 h1:+NSqMOr3GR6k1FdRhhnXrLfztGzuG+VuFDfa github.com/clipperhouse/stringish v0.1.1/go.mod h1:v/WhFtE1q0ovMta2+m+UbpZ+2/HEXNWYXQgCt4hdOzA= github.com/clipperhouse/uax29/v2 v2.3.0 h1:SNdx9DVUqMoBuBoW3iLOj4FQv3dN5mDtuqwuhIGpJy4= github.com/clipperhouse/uax29/v2 v2.3.0/go.mod h1:Wn1g7MK6OoeDT0vL+Q0SQLDz/KpfsVRgg6W7ihQeh4g= +github.com/cockroachdb/apd v1.1.0 h1:3LFP3629v+1aKXU5Q37mxmRxX/pIu1nijXydLShEq5I= github.com/cockroachdb/apd v1.1.0/go.mod h1:8Sl8LxpKi29FqWXR16WEFZRNSz3SoPzUzeMeY4+DwBQ= +github.com/containerd/errdefs v1.0.0 h1:tg5yIfIlQIrxYtu9ajqY42W3lpS19XqdxRQeEwYG8PI= +github.com/containerd/errdefs v1.0.0/go.mod h1:+YBYIdtsnF4Iw6nWZhJcqGSg/dwvV7tyJ/kCkyJ2k+M= +github.com/containerd/errdefs/pkg v0.3.0 h1:9IKJ06FvyNlexW690DXuQNx2KA2cUJXx151Xdx3ZPPE= +github.com/containerd/errdefs/pkg v0.3.0/go.mod h1:NJw6s9HwNuRhnjJhM7pylWwMyAkmCQvQ4GpJHEqRLVk= +github.com/containerd/typeurl/v2 v2.2.0 h1:6NBDbQzr7I5LHgp34xAXYF5DOTQDn05X58lsPEmzLso= +github.com/containerd/typeurl/v2 v2.2.0/go.mod h1:8XOOxnyatxSWuG8OfsZXVnAF4iZfedjS/8UHSPJnX4g= github.com/coreos/go-oidc/v3 v3.17.0 h1:hWBGaQfbi0iVviX4ibC7bk8OKT5qNr4klBaCHVNvehc= github.com/coreos/go-oidc/v3 v3.17.0/go.mod h1:wqPbKFrVnE90vty060SB40FCJ8fTHTxSwyXJqZH+sI8= github.com/coreos/go-systemd v0.0.0-20190321100706-95778dfbb74e/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4= +github.com/coreos/go-systemd v0.0.0-20190719114852-fd7a80b32e1f h1:JOrtw2xFKzlg+cbHpyrpLDmnN1HqhBfnX7WDiW7eG2c= github.com/coreos/go-systemd v0.0.0-20190719114852-fd7a80b32e1f/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4= github.com/cpuguy83/go-md2man/v2 v2.0.0-20190314233015-f79a8a8ca69d/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU= github.com/cpuguy83/go-md2man/v2 v2.0.6 h1:XJtiaUW6dEEqVuZiMTn1ldk455QWwEIsMIJlo5vtkx0= github.com/cpuguy83/go-md2man/v2 v2.0.6/go.mod h1:oOW0eioCTA6cOiMLiUPZOpcVxMig6NIQQ7OS05n1F4g= github.com/creack/pty v1.1.7/go.mod h1:lj5s0c3V2DBrqTV7llrYr5NG6My20zk30Fl46Y7DoTY= github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E= +github.com/creack/pty v1.1.24 h1:bJrF4RRfyJnbTJqzRLHzcGaZK1NeM5kTC9jGgovnR1s= +github.com/creack/pty v1.1.24/go.mod h1:08sCNb52WyoAwi2QDyzUCTgcvVFhUzewun7wtTfvcwE= github.com/cweill/gotests v1.9.0 h1:2B0mA22tbAZemMvOzbRzxehXecRrc6Y2j4GDsmoz23U= github.com/cweill/gotests v1.9.0/go.mod h1:ec4OTmXWVUEIznSTBJcO5s9df8C+4NGiEaUuVJW1pL0= github.com/d4l3k/messagediff v1.2.1 h1:ZcAIMYsUg0EAp9X+tt8/enBE/Q8Yd5kzPynLyKptt9U= @@ -122,7 +159,14 @@ github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f h1:lO4WD4F/r github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f/go.mod h1:cuUVRXasLTGF7a8hSLbxyZXjz+1KgoB3wDUb6vlszIc= github.com/disintegration/imaging v1.6.2 h1:w1LecBlG2Lnp8B3jk5zSuNqd7b4DXhcjwek1ei82L+c= github.com/disintegration/imaging v1.6.2/go.mod h1:44/5580QXChDfwIclfc/PCwrr44amcmDAg8hxG0Ewe4= +github.com/distribution/reference v0.6.0 h1:0IXCQ5g4/QMHHkarYzh5l+u8T3t73zM5QvfrDyIgxBk= +github.com/distribution/reference v0.6.0/go.mod h1:BbU0aIcezP1/5jX/8MP0YiH4SdvB5Y4f/wlDRiLyi3E= +github.com/dnaeon/go-vcr v1.2.0 h1:zHCHvJYTMh1N7xnV7zf1m1GPBF9Ad0Jk/whtQ1663qI= github.com/dnaeon/go-vcr v1.2.0/go.mod h1:R4UdLID7HZT3taECzJs4YgbbH6PIGXB6W/sc5OLb6RQ= +github.com/docker/go-connections v0.6.0 h1:LlMG9azAe1TqfR7sO+NJttz1gy6KO7VJBh+pMmjSD94= +github.com/docker/go-connections v0.6.0/go.mod h1:AahvXYshr6JgfUJGdDCs2b5EZG/vmaMAntpSFH5BFKE= +github.com/docker/go-units v0.5.0 h1:69rxXcBk27SvSaaxTtLh/8llcHD8vYHT7WSdRZ/jvr4= +github.com/docker/go-units v0.5.0/go.mod h1:fgPhTUdO+D/Jk86RDLlptpiXQzgHJF7gydDDbaIK4Dk= github.com/dustin/go-humanize v1.0.0/go.mod h1:HtrtbFcZ19U5GC7JDqmcUSB87Iq5E25KnS6fMYU6eOk= github.com/dustin/go-humanize v1.0.1 h1:GzkhY7T5VNhEkwH0PVJgjz+fX1rhBrR7pRT3mDkpeCY= github.com/dustin/go-humanize v1.0.1/go.mod h1:Mu1zIs6XwVuF/gI1OepvI0qD18qycQx+mFykh5fBlto= @@ -130,6 +174,8 @@ github.com/dustinkirkland/golang-petname v0.0.0-20240422154211-76c06c4bde6b h1:+ github.com/dustinkirkland/golang-petname v0.0.0-20240422154211-76c06c4bde6b/go.mod h1:8AuBTZBRSFqEYBPYULd+NN474/zZBLP+6WeT5S9xlAc= github.com/fatih/color v1.18.0 h1:S8gINlzdQ840/4pfAwic/ZE0djQEH3wM94VfqLTZcOM= github.com/fatih/color v1.18.0/go.mod h1:4FelSpRwEGDpQ12mAdzqdOukCy4u8WUtOY6lkT/6HfU= +github.com/felixge/httpsnoop v1.0.4 h1:NFTV2Zj1bL4mc9sqWACXbQFVBBg2W3GPvqp8/ESS2Wg= +github.com/felixge/httpsnoop v1.0.4/go.mod h1:m8KPJKqk1gH5J9DgRY2ASl2lWCfGKXixSwevea8zH2U= github.com/frankban/quicktest v1.14.6 h1:7Xjx+VpznH+oBnejlPUj8oUpdxnVs4f8XU8WnHkI4W8= github.com/frankban/quicktest v1.14.6/go.mod h1:4ptaffx2x8+WTWXmUCuVU6aPUX1/Mz7zb5vbUoiM6w0= github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo= @@ -142,6 +188,10 @@ github.com/ganigeorgiev/fexpr v0.5.0 h1:XA9JxtTE/Xm+g/JFI6RfZEHSiQlk+1glLvRK1Lpv github.com/ganigeorgiev/fexpr v0.5.0/go.mod h1:RyGiGqmeXhEQ6+mlGdnUleLHgtzzu/VGO2WtJkF5drE= github.com/getsentry/sentry-go v0.41.0 h1:q/dQZOlEIb4lhxQSjJhQqtRr3vwrJ6Ahe1C9zv+ryRo= github.com/getsentry/sentry-go v0.41.0/go.mod h1:eRXCoh3uvmjQLY6qu63BjUZnaBu5L5WhMV1RwYO8W5s= +github.com/gin-contrib/sse v0.1.0 h1:Y/yl/+YNO8GZSjAhjMsSuLt29uWRFHdHYUb5lYOV9qE= +github.com/gin-contrib/sse v0.1.0/go.mod h1:RHrZQHXnP2xjPF+u1gW/2HnVO7nvIa9PG3Gm+fLHvGI= +github.com/gin-gonic/gin v1.9.0 h1:OjyFBKICoexlu99ctXNR2gg+c5pKrKMuyjgARg9qeY8= +github.com/gin-gonic/gin v1.9.0/go.mod h1:W1Me9+hsUSyj3CePGrd1/QrKJMSJ1Tu/0hFEH89961k= github.com/go-asn1-ber/asn1-ber v1.5.8-0.20250403174932-29230038a667 h1:BP4M0CvQ4S3TGls2FvczZtj5Re/2ZzkV9VwqPHH/3Bo= github.com/go-asn1-ber/asn1-ber v1.5.8-0.20250403174932-29230038a667/go.mod h1:hEBeB/ic+5LoWskz+yKT7vGhhPYkProFKoKdwZRWMe0= github.com/go-chi/chi/v5 v5.2.2 h1:CMwsvRVTbXVytCk1Wd72Zy1LAsAh9GxMmSNWLHCG618= @@ -150,10 +200,17 @@ github.com/go-errors/errors v1.4.2 h1:J6MZopCL4uSllY1OfXM374weqZFFItUbrImctkmUxI github.com/go-errors/errors v1.4.2/go.mod h1:sIVyrIiJhuEF+Pj9Ebtd6P/rEYROXFi3BopGUQ5a5Og= github.com/go-jose/go-jose/v4 v4.1.3 h1:CVLmWDhDVRa6Mi/IgCgaopNosCaHz7zrMeF9MlZRkrs= github.com/go-jose/go-jose/v4 v4.1.3/go.mod h1:x4oUasVrzR7071A4TnHLGSPpNOm2a21K9Kf04k1rs08= +github.com/go-kit/log v0.1.0 h1:DGJh0Sm43HbOeYDNnVZFl8BvcYVvjD5bqYJvp0REbwQ= github.com/go-kit/log v0.1.0/go.mod h1:zbhenjAZHb184qTLMA9ZjW7ThYL0H2mk7Q6pNt4vbaY= github.com/go-ldap/ldap/v3 v3.4.12 h1:1b81mv7MagXZ7+1r7cLTWmyuTqVqdwbtJSjC0DAp9s4= github.com/go-ldap/ldap/v3 v3.4.12/go.mod h1:+SPAGcTtOfmGsCb3h1RFiq4xpp4N636G75OEace8lNo= +github.com/go-logfmt/logfmt v0.5.0 h1:TrB8swr/68K7m9CcGut2g3UOihhbcbiMAYiuTXdEih4= github.com/go-logfmt/logfmt v0.5.0/go.mod h1:wCYkCAKZfumFQihp8CzCvQ3paCTfi41vtzG1KdI/P7A= +github.com/go-logr/logr v1.2.2/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A= +github.com/go-logr/logr v1.4.3 h1:CjnDlHq8ikf6E492q6eKboGOC0T8CDaOvkHCIg8idEI= +github.com/go-logr/logr v1.4.3/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY= +github.com/go-logr/stdr v1.2.2 h1:hSWxHoqTgW2S2qGc0LTAI563KZ5YKYRhT3MFKZMbjag= +github.com/go-logr/stdr v1.2.2/go.mod h1:mMo/vtBO5dYbehREoey6XUKy/eSumjCCveDpRre4VKE= github.com/go-openapi/jsonpointer v0.19.3/go.mod h1:Pl9vOtqEWErmShwVjC8pYs9cog34VGT37dQOVbmoatg= github.com/go-openapi/jsonpointer v0.19.5/go.mod h1:Pl9vOtqEWErmShwVjC8pYs9cog34VGT37dQOVbmoatg= github.com/go-openapi/jsonpointer v0.21.0 h1:YgdVicSA9vH5RiHs9TZW5oyafXZFc6+2Vc1rr/O9oNQ= @@ -167,10 +224,18 @@ github.com/go-openapi/swag v0.19.5/go.mod h1:POnQmlKehdgb5mhVOsnJFsivZCEZ/vjK9gh github.com/go-openapi/swag v0.19.15/go.mod h1:QYRuS/SOXUCsnplDa677K7+DxSOj6IPNl/eQntq43wQ= github.com/go-openapi/swag v0.23.0 h1:vsEVJDUo2hPJ2tu0/Xc+4noaxyEffXNIs3cOULZ+GrE= github.com/go-openapi/swag v0.23.0/go.mod h1:esZ8ITTYEsH1V2trKHjAN8Ai7xHb8RV+YSZ577vPjgQ= +github.com/go-playground/locales v0.14.1 h1:EWaQ/wswjilfKLTECiXz7Rh+3BjFhfDFKv/oXslEjJA= +github.com/go-playground/locales v0.14.1/go.mod h1:hxrqLVvrK65+Rwrd5Fc6F2O76J/NuW9t0sjnWqG1slY= +github.com/go-playground/universal-translator v0.18.1 h1:Bcnm0ZwsGyWbCzImXv+pAJnYK9S473LQFuzCbDbfSFY= +github.com/go-playground/universal-translator v0.18.1/go.mod h1:xekY+UJKNuX9WP91TpwSH2VMlDf28Uj24BCp08ZFTUY= +github.com/go-playground/validator/v10 v10.11.2 h1:q3SHpufmypg+erIExEKUmsgmhDTyhcJ38oeKGACXohU= +github.com/go-playground/validator/v10 v10.11.2/go.mod h1:NieE624vt4SCTJtD87arVLvdmjPAeV8BQlHtMnw9D7s= github.com/go-sql-driver/mysql v1.7.0/go.mod h1:OXbVy3sEdcQ2Doequ6Z5BW6fXNQTmx+9S1MCJN5yJMI= github.com/go-sql-driver/mysql v1.9.3 h1:U/N249h2WzJ3Ukj8SowVFjdtZKfu9vlLZxjPXV1aweo= github.com/go-sql-driver/mysql v1.9.3/go.mod h1:qn46aNg1333BRMNU69Lq93t8du/dwxI64Gl8i5p1WMU= +github.com/go-stack/stack v1.8.0 h1:5SgMzNM5HxrEjV0ww2lTmX6E2Izsfxas4+YHWRs3Lsk= github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY= +github.com/go-task/slim-sprig v0.0.0-20210107165309-348f09dbbbc0 h1:p104kn46Q8WdvHunIJ9dAyjPVtrBPhSr3KT2yUst43I= github.com/go-task/slim-sprig v0.0.0-20210107165309-348f09dbbbc0/go.mod h1:fyg7847qk6SyHyPtNmDHnmrv/HOrqktSC+C9fM+CJOE= github.com/go-testfixtures/testfixtures/v3 v3.19.0 h1:/Y0bars250zggm+1A2PvwaJQsJel7/tS4D/Hhwt66Bc= github.com/go-testfixtures/testfixtures/v3 v3.19.0/go.mod h1:4/hVAuX2As0/ej3fLuAd+IvoCXV7/h2cj5nInI11uxM= @@ -184,7 +249,10 @@ github.com/goccy/go-json v0.10.5 h1:Fq85nIqj+gXn/S5ahsiTlK3TmC85qgirsdTP/+DeaC4= github.com/goccy/go-json v0.10.5/go.mod h1:oq7eo15ShAhp70Anwd5lgX2pLfOS3QCiwU/PULtXL6M= github.com/goccy/go-yaml v1.18.0 h1:8W7wMFS12Pcas7KU+VVkaiCng+kG8QiFeFwzFb+rwuw= github.com/goccy/go-yaml v1.18.0/go.mod h1:XBurs7gK8ATbW4ZPGKgcbrY1Br56PdM69F7LkFRi1kA= +github.com/gofrs/uuid v4.0.0+incompatible h1:1SD/1F5pU8p29ybwgQSwpQk+mwdRrXCYuPhW6m+TnJw= github.com/gofrs/uuid v4.0.0+incompatible/go.mod h1:b2aQJv3Z4Fp6yNu3cdSllBxTCLRxnplIgP/c0N/04lM= +github.com/gogo/protobuf v1.3.2 h1:Ov1cvc58UF3b5XjBnZv7+opcTcQFZebYjWzi34vdm4Q= +github.com/gogo/protobuf v1.3.2/go.mod h1:P1XiOD3dCwIKUDQYPy72D8LYyHL2YPYrpS2s69NZV8Q= github.com/golang-jwt/jwt/v5 v5.3.0 h1:pv4AsKCKKZuqlgs5sUmn4x8UlGa0kEVt/puTpKx9vvo= github.com/golang-jwt/jwt/v5 v5.3.0/go.mod h1:fxCRLWMO43lRc8nhHWY6LGqRcf+1gQWArsqaEUEa5bE= github.com/golang-sql/civil v0.0.0-20190719163853-cb61b32ac6fe/go.mod h1:8vg3r2VgvsThLBIFL93Qb5yWzgyZWhEmBwUJWevAkK0= @@ -201,6 +269,8 @@ github.com/golang/protobuf v1.4.0/go.mod h1:jodUvKwWbYaEsadDk5Fwe5c77LiNKVO9IDvq github.com/golang/protobuf v1.4.2/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI= github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk= github.com/golang/protobuf v1.5.2/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY= +github.com/golang/protobuf v1.5.4 h1:i7eJL8qZTpSEXOPTxNKhASYpMn+8e5Q6AdndVa1dWek= +github.com/golang/protobuf v1.5.4/go.mod h1:lnTiLA8Wa4RWRcIUkrtSVa5nRhsEGBg48fD6rSs7xps= github.com/golang/snappy v0.0.0-20180518054509-2e65f85255db/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= github.com/golang/snappy v0.0.1/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= github.com/golang/snappy v0.0.4 h1:yAGX7huGHXlcLOEtBnF4w7FQwA26wojNCwOYAEhLjQM= @@ -213,8 +283,11 @@ github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/ github.com/google/go-cmp v0.5.9/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= github.com/google/go-cmp v0.7.0 h1:wk8382ETsv4JYUZwIsn6YpYiWiBsYLSJiTsyBybVuN8= github.com/google/go-cmp v0.7.0/go.mod h1:pXiqmnSA92OHEEa9HXL2W4E7lf9JzCmGVUdgjX3N/iU= +github.com/google/gofuzz v1.0.0 h1:A8PeW59pxE9IoFRqBp37U+mSNaQoZ46F1f0f863XSXw= github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= +github.com/google/pprof v0.0.0-20221118152302-e6195bd50e26 h1:Xim43kblpZXfIBQsbuBVKCudVG457BR2GZFIz3uw3hQ= github.com/google/pprof v0.0.0-20221118152302-e6195bd50e26/go.mod h1:dDKJzRmX4S37WGHujM7tX//fmj1uioxKzKxz3lo4HJo= +github.com/google/renameio v0.1.0 h1:GOZbcHa3HfsPKPlmyPyN2KEohoMXOhdMbHrvbpl2QaA= github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI= github.com/google/uuid v1.2.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/google/uuid v1.3.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= @@ -228,6 +301,7 @@ github.com/hashicorp/go-version v1.8.0 h1:KAkNb1HAiZd1ukkxDFGmokVZe1Xy9HG6NUp+bP github.com/hashicorp/go-version v1.8.0/go.mod h1:fltr4n8CU8Ke44wwGCBoEymUuxUHl09ZGVZPK5anwXA= github.com/hhsnopek/etag v0.0.0-20171206181245-aea95f647346 h1:Odeq5rB6OZSkib5gqTG+EM1iF0bUVjYYd33XB1ULv00= github.com/hhsnopek/etag v0.0.0-20171206181245-aea95f647346/go.mod h1:4ggHM2qnyyZjenBb7RpwVzIj+JMsu9kHCVxMjB30hGs= +github.com/hpcloud/tail v1.0.0 h1:nfCOvKYfkgYP8hkirhJocXT2+zOD8yUNjXaWfTlyFKI= github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU= github.com/huandu/go-assert v1.1.5 h1:fjemmA7sSfYHJD7CUqs9qTwwfdNAx7/j2/ZlHXzNB3c= github.com/huandu/go-assert v1.1.5/go.mod h1:yOLvuqZwmcHIC5rIzrBhT7D3Q9c3GFnd0JrPVhn/06U= @@ -237,11 +311,14 @@ github.com/huandu/go-clone/generic v1.7.3 h1:hXbg87J1nWwwHO2vGD5PAnBohQCfltl+fOE github.com/huandu/go-clone/generic v1.7.3/go.mod h1:GnX7Bo9qvXKm2f3OJybqcbgj6YmA/kuEd/pw5JbsB/I= github.com/iancoleman/strcase v0.3.0 h1:nTXanmYxhfFAMjZL34Ov6gkzEsSJZ5DbhxWjvSASxEI= github.com/iancoleman/strcase v0.3.0/go.mod h1:iwCmte+B7n89clKwxIoIXy/HfoL7AsD47ZCWhYzw7ho= +github.com/ianlancetaylor/demangle v0.0.0-20220319035150-800ac71e25c2 h1:rcanfLhLDA8nozr/K289V1zcntHr3V+SHlXwzz1ZI2g= github.com/ianlancetaylor/demangle v0.0.0-20220319035150-800ac71e25c2/go.mod h1:aYm2/VgdVmcIU8iMfdMvDMsRAQjcfZSKFby6HOFvi/w= github.com/inconshreveable/mousetrap v1.1.0 h1:wN+x4NVGpMsO7ErUn/mUI3vEoE6Jt13X2s0bqwp9tc8= github.com/inconshreveable/mousetrap v1.1.0/go.mod h1:vpF70FUmC8bwa3OWnCshd2FqLfsEA9PFc4w1p2J65bw= +github.com/jackc/chunkreader v1.0.0 h1:4s39bBR8ByfqH+DKm8rQA3E1LHZWB9XWcrz8fqaZbe0= github.com/jackc/chunkreader v1.0.0/go.mod h1:RT6O25fNZIuasFJRyZ4R/Y2BbhasbmZXF9QQ7T3kePo= github.com/jackc/chunkreader/v2 v2.0.0/go.mod h1:odVSm741yZoC3dpHEUXIqA9tQRhFrgOHwnPIn9lDKlk= +github.com/jackc/chunkreader/v2 v2.0.1 h1:i+RDz65UE+mmpjTfyz0MoVTnzeYxroil2G82ki7MGG8= github.com/jackc/chunkreader/v2 v2.0.1/go.mod h1:odVSm741yZoC3dpHEUXIqA9tQRhFrgOHwnPIn9lDKlk= github.com/jackc/pgconn v0.0.0-20190420214824-7e0022ef6ba3/go.mod h1:jkELnwuX+w9qN5YIfX0fl88Ehu4XC3keFuOJJk9pcnA= github.com/jackc/pgconn v0.0.0-20190824142844-760dd75542eb/go.mod h1:lLjNuW/+OfW9/pnVKPazfWOgNfH2aPem8YQ7ilXGvJE= @@ -249,12 +326,17 @@ github.com/jackc/pgconn v0.0.0-20190831204454-2fabfa3c18b7/go.mod h1:ZJKsE/KZfsU github.com/jackc/pgconn v1.8.0/go.mod h1:1C2Pb36bGIP9QHGBYCjnyhqu7Rv3sGshaQUvmfGIB/o= github.com/jackc/pgconn v1.9.0/go.mod h1:YctiPyvzfU11JFxoXokUOOKQXQmDMoJL9vJzHH8/2JY= github.com/jackc/pgconn v1.9.1-0.20210724152538-d89c8390a530/go.mod h1:4z2w8XhRbP1hYxkpTuBjTS3ne3J48K83+u0zoyvg2pI= +github.com/jackc/pgconn v1.14.0 h1:vrbA9Ud87g6JdFWkHTJXppVce58qPIdP7N8y0Ml/A7Q= github.com/jackc/pgconn v1.14.0/go.mod h1:9mBNlny0UvkgJdCDvdVHYSjI+8tD2rnKK69Wz8ti++E= +github.com/jackc/pgio v1.0.0 h1:g12B9UwVnzGhueNavwioyEEpAmqMe1E/BN9ES+8ovkE= github.com/jackc/pgio v1.0.0/go.mod h1:oP+2QK2wFfUWgr+gxjoBH9KGBb31Eio69xUb0w5bYf8= github.com/jackc/pgmock v0.0.0-20190831213851-13a1b77aafa2/go.mod h1:fGZlG77KXmcq05nJLRkk0+p82V8B8Dw8KN2/V9c/OAE= github.com/jackc/pgmock v0.0.0-20201204152224-4fe30f7445fd/go.mod h1:hrBW0Enj2AZTNpt/7Y5rr2xe/9Mn757Wtb2xeBzPv2c= +github.com/jackc/pgmock v0.0.0-20210724152146-4ad1a8207f65 h1:DadwsjnMwFjfWc9y5Wi/+Zz7xoE5ALHsRQlOctkOiHc= github.com/jackc/pgmock v0.0.0-20210724152146-4ad1a8207f65/go.mod h1:5R2h2EEX+qri8jOWMbJCtaPWkrrNc7OHwsp2TCqp7ak= +github.com/jackc/pgpassfile v1.0.0 h1:/6Hmqy13Ss2zCq62VdNG8tM1wchn8zjSGOBJ6icpsIM= github.com/jackc/pgpassfile v1.0.0/go.mod h1:CEx0iS5ambNFdcRtxPj5JhEz+xB6uRky5eyVu/W2HEg= +github.com/jackc/pgproto3 v1.1.0 h1:FYYE4yRw+AgI8wXIinMlNjBbp/UitDJwfj5LqqewP1A= github.com/jackc/pgproto3 v1.1.0/go.mod h1:eR5FA3leWg7p9aeAqi37XOTgTIbkABlvcPB3E5rlc78= github.com/jackc/pgproto3/v2 v2.0.0-alpha1.0.20190420180111-c116219b62db/go.mod h1:bhq50y+xrl9n5mRYyCBFKkpRVTLYJVWeCc+mEAI3yXA= github.com/jackc/pgproto3/v2 v2.0.0-alpha1.0.20190609003834-432c2951c711/go.mod h1:uH0AWtUmuShn0bcesswc4aBTWGvw0cAxIJp+6OB//Wg= @@ -262,23 +344,33 @@ github.com/jackc/pgproto3/v2 v2.0.0-rc3/go.mod h1:ryONWYqW6dqSg1Lw6vXNMXoBJhpzvW github.com/jackc/pgproto3/v2 v2.0.0-rc3.0.20190831210041-4c03ce451f29/go.mod h1:ryONWYqW6dqSg1Lw6vXNMXoBJhpzvWKnT95C46ckYeM= github.com/jackc/pgproto3/v2 v2.0.6/go.mod h1:WfJCnwN3HIg9Ish/j3sgWXnAfK8A9Y0bwXYU5xKaEdA= github.com/jackc/pgproto3/v2 v2.1.1/go.mod h1:WfJCnwN3HIg9Ish/j3sgWXnAfK8A9Y0bwXYU5xKaEdA= +github.com/jackc/pgproto3/v2 v2.3.2 h1:7eY55bdBeCz1F2fTzSz69QC+pG46jYq9/jtSPiJ5nn0= github.com/jackc/pgproto3/v2 v2.3.2/go.mod h1:WfJCnwN3HIg9Ish/j3sgWXnAfK8A9Y0bwXYU5xKaEdA= github.com/jackc/pgservicefile v0.0.0-20200714003250-2b9c44734f2b/go.mod h1:vsD4gTJCa9TptPL8sPkXrLZ+hDuNrZCnj29CQpr4X1E= github.com/jackc/pgservicefile v0.0.0-20221227161230-091c0ba34f0a/go.mod h1:5TJZWKEWniPve33vlWYSoGYefn3gLQRzjfDlhSJ9ZKM= +github.com/jackc/pgservicefile v0.0.0-20240606120523-5a60cdf6a761 h1:iCEnooe7UlwOQYpKFhBabPMi4aNAfoODPEFNiAnClxo= +github.com/jackc/pgservicefile v0.0.0-20240606120523-5a60cdf6a761/go.mod h1:5TJZWKEWniPve33vlWYSoGYefn3gLQRzjfDlhSJ9ZKM= github.com/jackc/pgtype v0.0.0-20190421001408-4ed0de4755e0/go.mod h1:hdSHsc1V01CGwFsrv11mJRHWJ6aifDLfdV3aVjFF0zg= github.com/jackc/pgtype v0.0.0-20190824184912-ab885b375b90/go.mod h1:KcahbBH1nCMSo2DXpzsoWOAfFkdEtEJpPbVLq8eE+mc= github.com/jackc/pgtype v0.0.0-20190828014616-a8802b16cc59/go.mod h1:MWlu30kVJrUS8lot6TQqcg7mtthZ9T0EoIBFiJcmcyw= github.com/jackc/pgtype v1.8.1-0.20210724151600-32e20a603178/go.mod h1:C516IlIV9NKqfsMCXTdChteoXmwgUceqaLfjg2e3NlM= +github.com/jackc/pgtype v1.14.0 h1:y+xUdabmyMkJLyApYuPj38mW+aAIqCe5uuBB51rH3Vw= github.com/jackc/pgtype v1.14.0/go.mod h1:LUMuVrfsFfdKGLw+AFFVv6KtHOFMwRgDDzBt76IqCA4= github.com/jackc/pgx/v4 v4.0.0-20190420224344-cc3461e65d96/go.mod h1:mdxmSJJuR08CZQyj1PVQBHy9XOp5p8/SHH6a0psbY9Y= github.com/jackc/pgx/v4 v4.0.0-20190421002000-1b8f0016e912/go.mod h1:no/Y67Jkk/9WuGR0JG/JseM9irFbnEPbuWV2EELPNuM= github.com/jackc/pgx/v4 v4.0.0-pre1.0.20190824185557-6972a5742186/go.mod h1:X+GQnOEnf1dqHGpw7JmHqHc1NxDoalibchSk9/RWuDc= github.com/jackc/pgx/v4 v4.12.1-0.20210724153913-640aa07df17c/go.mod h1:1QD0+tgSXP7iUjYm9C1NxKhny7lq6ee99u/z+IHFcgs= +github.com/jackc/pgx/v4 v4.18.0 h1:Ltaa1ePvc7msFGALnCrqKJVEByu/qYh5jJBYcDtAno4= github.com/jackc/pgx/v4 v4.18.0/go.mod h1:FydWkUyadDmdNH/mHnGob881GawxeEm7TcMCzkb+qQE= +github.com/jackc/pgx/v5 v5.6.0 h1:SWJzexBzPL5jb0GEsrPMLIsi/3jOo7RHlzTjcAeDrPY= +github.com/jackc/pgx/v5 v5.6.0/go.mod h1:DNZ/vlrUnhWCoFGxHAG8U2ljioxukquj7utPDgtQdTw= github.com/jackc/puddle v0.0.0-20190413234325-e4ced69a3a2b/go.mod h1:m4B5Dj62Y0fbyuIc15OsIqK0+JU8nkqQjsgx7dvjSWk= github.com/jackc/puddle v0.0.0-20190608224051-11cab39313c9/go.mod h1:m4B5Dj62Y0fbyuIc15OsIqK0+JU8nkqQjsgx7dvjSWk= github.com/jackc/puddle v1.1.3/go.mod h1:m4B5Dj62Y0fbyuIc15OsIqK0+JU8nkqQjsgx7dvjSWk= +github.com/jackc/puddle v1.3.0 h1:eHK/5clGOatcjX3oWGBO/MpxpbHzSwud5EWTSCI+MX0= github.com/jackc/puddle v1.3.0/go.mod h1:m4B5Dj62Y0fbyuIc15OsIqK0+JU8nkqQjsgx7dvjSWk= +github.com/jackc/puddle/v2 v2.2.2 h1:PR8nw+E/1w0GLuRFSmiioY6UooMp6KJv0/61nB7icHo= +github.com/jackc/puddle/v2 v2.2.2/go.mod h1:vriiEXHvEE654aYKXXjOvZM39qJ0q+azkZFrfEOc3H4= github.com/jaswdr/faker/v2 v2.9.1 h1:J0Rjqb2/FquZnoZplzkGVL5LmhNkeIpvsSMoJKzn+8E= github.com/jaswdr/faker/v2 v2.9.1/go.mod h1:jZq+qzNQr8/P+5fHd9t3txe2GNPnthrTfohtnJ7B+68= github.com/jcmturner/aescts/v2 v2.0.0 h1:9YKLH6ey7H4eDBXW8khjYslgyqG2xZikXP0EQFKrle8= @@ -299,22 +391,34 @@ github.com/joho/godotenv v1.3.0 h1:Zjp+RcGpHhGlrMbJzXTrZZPrWj+1vfm90La1wgB6Bhc= github.com/joho/godotenv v1.3.0/go.mod h1:7hK45KPybAkOC6peb+G5yklZfMxEjkZhHbwpqxOKXbg= github.com/josharian/intern v1.0.0 h1:vlS4z54oSdjm0bgjRigI+G1HpF+tI+9rE5LLzOg8HmY= github.com/josharian/intern v1.0.0/go.mod h1:5DoeVV0s6jJacbCEi61lwdGj/aVlrQvzHFFd8Hwg//Y= +github.com/jpillora/backoff v1.0.0 h1:uvFg412JmmHBHw7iwprIxkPMI+sGQ4kzOWsMeHnm2EA= +github.com/jpillora/backoff v1.0.0/go.mod h1:J/6gKK9jxlEcS3zixgDgUAsiuZ7yrSoa/FX5e0EB2j4= +github.com/json-iterator/go v1.1.12 h1:PV8peI4a0ysnczrg+LtxykD8LfKY9ML6u2jnxaEnrnM= github.com/json-iterator/go v1.1.12/go.mod h1:e30LSqwooZae/UwlEbR2852Gd8hjQvJoHmT4TnhNGBo= github.com/jszwedko/go-datemath v0.1.1-0.20230526204004-640a500621d6 h1:SwcnSwBR7X/5EHJQlXBockkJVIMRVt5yKaesBPMtyZQ= github.com/jszwedko/go-datemath v0.1.1-0.20230526204004-640a500621d6/go.mod h1:WrYiIuiXUMIvTDAQw97C+9l0CnBmCcvosPjN3XDqS/o= +github.com/julienschmidt/httprouter v1.3.0 h1:U0609e9tgbseu3rBINet9P48AI/D3oJs4dN7jwJOQ1U= +github.com/julienschmidt/httprouter v1.3.0/go.mod h1:JR6WtHb+2LUe8TCKY3cZOxFyyO8IZAc4RVcycCCAKdM= +github.com/k0kubun/go-ansi v0.0.0-20180517002512-3bf9e2903213 h1:qGQQKEcAR99REcMpsXCp3lJ03zYT1PkRd3kQGPn9GVg= +github.com/k0kubun/go-ansi v0.0.0-20180517002512-3bf9e2903213/go.mod h1:vNUNkEQ1e29fT/6vq2aBdFsgNPmy8qMdSay1npru+Sw= github.com/kballard/go-shellquote v0.0.0-20180428030007-95032a82bc51 h1:Z9n2FFNUXsshfwJMBgNA0RU6/i7WVaAegv3PtuIHPMs= github.com/kballard/go-shellquote v0.0.0-20180428030007-95032a82bc51/go.mod h1:CzGEWj7cYgsdH8dAjBGEr58BoE7ScuLd+fwFZ44+/x8= +github.com/kisielk/gotool v1.0.0 h1:AV2c/EiW3KqPNT9ZKl07ehoAGi4C5/01Cfbblndcapg= github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck= github.com/klauspost/compress v1.18.0 h1:c/Cqfb0r+Yi+JtIEq73FWXVkRonBlf0CRNYc8Zttxdo= github.com/klauspost/compress v1.18.0/go.mod h1:2Pp+KzxcywXVXMr50+X0Q/Lsb43OQHYWRCY2AiWywWQ= +github.com/klauspost/cpuid/v2 v2.0.9 h1:lgaqFMSdTdQYdZ04uHyN2d/eKdOMyi2YLSvlQIBFYa4= +github.com/klauspost/cpuid/v2 v2.0.9/go.mod h1:FInQzS24/EEf25PyTYn52gqo7WaD8xa0213Md/qVLRg= github.com/kolaente/caldav-go v3.0.1-0.20190610114120-2a4eb8b5dcc9+incompatible h1:q7DbyV+sFjEoTuuUdRDNl2nlyfztkZgxVVCV7JhzIkY= github.com/kolaente/caldav-go v3.0.1-0.20190610114120-2a4eb8b5dcc9+incompatible/go.mod h1:y1UhTNI4g0hVymJrI6yJ5/ohy09hNBeU8iJEZjgdDOw= github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= +github.com/konsorten/go-windows-terminal-sequences v1.0.2 h1:DB17ag19krx9CFsz4o3enTrPXyIXCl+2iCXH/aMAp9s= github.com/konsorten/go-windows-terminal-sequences v1.0.2/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE= github.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk= github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= +github.com/kr/pty v1.1.8 h1:AkaSdXYQOWeaO3neb8EM634ahkXXe3jYbVh/F9lq+GI= github.com/kr/pty v1.1.8/go.mod h1:O1sed60cT9XZ5uDucP5qwvh+TE3NnUj51EiZO/lmSfw= github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= @@ -327,6 +431,8 @@ github.com/labstack/echo/v5 v5.0.3 h1:Jql8sDtCYXrhh2Mbs6jKwjR6r7X8FSQQmch+w6QS7k github.com/labstack/echo/v5 v5.0.3/go.mod h1:SyvlSdObGjRXeQfCCXW/sybkZdOOQZBmpKF0bvALaeo= github.com/laurent22/ical-go v0.1.1-0.20181107184520-7e5d6ade8eef h1:RZnRnSID1skF35j/15KJ6hKZkdIC/teQClJK5wP5LU4= github.com/laurent22/ical-go v0.1.1-0.20181107184520-7e5d6ade8eef/go.mod h1:4LATl0uhhtytR6p9n1AlktDyIz4u2iUnWEdI3L/hXiw= +github.com/leodido/go-urn v1.2.1 h1:BqpAaACuzVSgi/VLzGZIobT2z4v53pjosyNd9Yv6n/w= +github.com/leodido/go-urn v1.2.1/go.mod h1:zt4jvISO2HfUBqxjfIshjdMTYS56ZS/qv49ictyFfxY= github.com/lib/pq v1.0.0/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo= github.com/lib/pq v1.1.0/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo= github.com/lib/pq v1.2.0/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo= @@ -365,16 +471,32 @@ github.com/mattn/go-sqlite3 v1.14.33 h1:A5blZ5ulQo2AtayQ9/limgHEkFreKj1Dv226a1K7 github.com/mattn/go-sqlite3 v1.14.33/go.mod h1:Uh1q+B4BYcTPb+yiD3kU8Ct7aC0hY9fxUwlHK0RXw+Y= github.com/microcosm-cc/bluemonday v1.0.27 h1:MpEUotklkwCSLeH+Qdx1VJgNqLlpY2KXwXFM08ygZfk= github.com/microcosm-cc/bluemonday v1.0.27/go.mod h1:jFi9vgW+H7c3V0lb6nR74Ib/DIB5OBs92Dimizgw2cA= +github.com/microsoft/go-mssqldb v1.8.2 h1:236sewazvC8FvG6Dr3bszrVhMkAl4KYImryLkRMCd0I= +github.com/microsoft/go-mssqldb v1.8.2/go.mod h1:vp38dT33FGfVotRiTmDo3bFyaHq+p3LektQrjTULowo= github.com/mitchellh/colorstring v0.0.0-20190213212951-d06e56a500db h1:62I3jR2EmQ4l5rM/4FEfDWcRD+abF5XlKShorW5LRoQ= github.com/mitchellh/colorstring v0.0.0-20190213212951-d06e56a500db/go.mod h1:l0dey0ia/Uv7NcFFVbCLtqEBQbrT4OCwCSKTEv6enCw= +github.com/moby/docker-image-spec v1.3.1 h1:jMKff3w6PgbfSa69GfNg+zN/XLhfXJGnEx3Nl2EsFP0= +github.com/moby/docker-image-spec v1.3.1/go.mod h1:eKmb5VW8vQEh/BAr2yvVNvuiJuY6UIocYsFu/DxxRpo= +github.com/moby/moby/api v1.53.0 h1:PihqG1ncw4W+8mZs69jlwGXdaYBeb5brF6BL7mPIS/w= +github.com/moby/moby/api v1.53.0/go.mod h1:8mb+ReTlisw4pS6BRzCMts5M49W5M7bKt1cJy/YbAqc= +github.com/moby/moby/client v0.2.2 h1:Pt4hRMCAIlyjL3cr8M5TrXCwKzguebPAc2do2ur7dEM= +github.com/moby/moby/client v0.2.2/go.mod h1:2EkIPVNCqR05CMIzL1mfA07t0HvVUUOl85pasRz/GmQ= +github.com/moby/term v0.5.2 h1:6qk3FJAFDs6i/q3W/pQ97SX192qKfZgGjCQqfCJkgzQ= +github.com/moby/term v0.5.2/go.mod h1:d3djjFCrjnB+fl8NJux+EJzu0msscUP+f8it8hPkFLc= github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= +github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd h1:TRLaZ9cD/w8PVh93nsPXa1VrQ6jlwL5oN8l14QlcNfg= github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= +github.com/modern-go/reflect2 v1.0.2 h1:xBagoLtFs94CBntxluKeaWgTMpvLxC4ur3nMaC9Gz0M= github.com/modern-go/reflect2 v1.0.2/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk= +github.com/modocache/gover v0.0.0-20171022184752-b58185e213c5 h1:8Q0qkMVC/MmWkpIdlvZgcv2o2jrlF6zqVOh7W5YHdMA= github.com/modocache/gover v0.0.0-20171022184752-b58185e213c5/go.mod h1:caMODM3PzxT8aQXRPkAt8xlV/e7d7w8GM5g0fa5F0D8= github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 h1:C3w9PqII01/Oq1c1nUAm88MOHcQC9l5mIlSMApZMrHA= github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822/go.mod h1:+n7T8mK8HuQTcFwEeznm/DIxMOiR9yIdICNftLE1DvQ= +github.com/mwitkow/go-conntrack v0.0.0-20190716064945-2f068394615f h1:KUppIJq7/+SVif2QVs3tOP0zanoHgBEVAwHxUSIzRqU= +github.com/mwitkow/go-conntrack v0.0.0-20190716064945-2f068394615f/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U= github.com/ncruces/go-strftime v0.1.9 h1:bY0MQC28UADQmHmaF5dgpLmImcShSi2kHU9XLdhx/f4= github.com/ncruces/go-strftime v0.1.9/go.mod h1:Fwc5htZGVVkseilnfgOVb9mKy6w1naJmn9CehxcKcls= +github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e h1:fD57ERR4JtEqsWbfPhv4DMiApHyliiK5xCTNVSPiaAs= github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e/go.mod h1:zD1mROLANZcx1PVRCS0qkT7pwLkGfwJo4zjcN/Tysno= github.com/nxadm/tail v1.4.4/go.mod h1:kenIhsEOeOJmVchQTgglprH7qJGnHDVpk1VPCcaMI8A= github.com/nxadm/tail v1.4.8 h1:nPr65rt6Y5JFSKQO7qToXr7pePgD6Gwiw05lkbyAQTE= @@ -389,6 +511,8 @@ github.com/olekukonko/ll v0.1.4-0.20260115111900-9e59c2286df0 h1:jrYnow5+hy3WRDC github.com/olekukonko/ll v0.1.4-0.20260115111900-9e59c2286df0/go.mod h1:b52bVQRRPObe+yyBl0TxNfhesL0nedD4Cht0/zx55Ew= github.com/olekukonko/tablewriter v1.1.3 h1:VSHhghXxrP0JHl+0NnKid7WoEmd9/urKRJLysb70nnA= github.com/olekukonko/tablewriter v1.1.3/go.mod h1:9VU0knjhmMkXjnMKrZ3+L2JhhtsQ/L38BbL3CRNE8tM= +github.com/olekukonko/ts v0.0.0-20171002115256-78ecb04241c0 h1:LiZB1h0GIcudcDci2bxbqI6DXV8bF8POAnArqvRrIyw= +github.com/olekukonko/ts v0.0.0-20171002115256-78ecb04241c0/go.mod h1:F/7q8/HZz+TXjlsoZQQKVYvXTZaFH4QRa3y+j1p7MS0= github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= github.com/onsi/ginkgo v1.7.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= github.com/onsi/ginkgo v1.12.1/go.mod h1:zj2OWP4+oCPe1qIXoGWkgMRwljMUYCdkwsT2108oapk= @@ -399,10 +523,15 @@ github.com/onsi/gomega v1.7.1/go.mod h1:XdKZgCCFLUoM/7CFJVPcG8C1xQ1AJ0vpAezJrB7J github.com/onsi/gomega v1.10.1/go.mod h1:iN09h71vgCQne3DLsj+A5owkum+a2tYe+TOCB1ybHNo= github.com/onsi/gomega v1.16.0 h1:6gjqkI8iiRHMvdccRJM8rVKjCWk6ZIm6FTm3ddIe4/c= github.com/onsi/gomega v1.16.0/go.mod h1:HnhC7FXeEQY45zxNK3PPoIUhzk/80Xly9PcubAlGdZY= +github.com/opencontainers/go-digest v1.0.0 h1:apOUWs51W5PlhuyGyz9FCeeBIOUDA/6nW8Oi/yOhh5U= +github.com/opencontainers/go-digest v1.0.0/go.mod h1:0JzlMkj0TRzQZfJkVvzbP0HBR3IKzErnv2BNG4W4MAM= +github.com/opencontainers/image-spec v1.1.1 h1:y0fUlFfIZhPF1W537XOLg0/fcx6zcHCJwooC2xJA040= +github.com/opencontainers/image-spec v1.1.1/go.mod h1:qpqAh3Dmcf36wStyyWU+kCeDgrGnAve2nCC8+7h8Q0M= github.com/pelletier/go-toml/v2 v2.2.4 h1:mye9XuhQ6gvn5h28+VilKrrPoQVanw5PMw/TB0t5Ec4= github.com/pelletier/go-toml/v2 v2.2.4/go.mod h1:2gIqNv+qfxSVS7cM2xJQKtLSTLUE9V8t9Stt+h56mCY= github.com/pingcap/errors v0.11.4 h1:lFuQV/oaUMGcD2tqt+01ROSmJs75VG1ToEOkZIZ4nE4= github.com/pingcap/errors v0.11.4/go.mod h1:Oi8TUi2kEtXXLMJk9l1cGmz20kV3TaQ0usTwv5KuLY8= +github.com/pkg/browser v0.0.0-20180916011732-0a3d74bf9ce4 h1:49lOXmGaUpV9Fz3gd7TFZY106KVlPVa5jcYD1gaQf98= github.com/pkg/browser v0.0.0-20180916011732-0a3d74bf9ce4/go.mod h1:4OwLy04Bl9Ef3GJJCoec+30X3LQs/0/m4HFRt/2LUSA= github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4= @@ -432,23 +561,37 @@ github.com/robfig/cron/v3 v3.0.1/go.mod h1:eQICP3HwyT7UooqI/z+Ov+PtYAWygg1TEWWzG github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4= github.com/rogpeppe/go-internal v1.13.2-0.20241226121412-a5dc8ff20d0a h1:w3tdWGKbLGBPtR/8/oO74W6hmz0qE5q0z9aqSAewaaM= github.com/rogpeppe/go-internal v1.13.2-0.20241226121412-a5dc8ff20d0a/go.mod h1:S8kfXMp+yh77OxPD4fdM6YUknrZpQxLhvxzS4gDHENY= +github.com/rogpeppe/go-internal v1.14.1 h1:UQB4HGPB6osV0SQTLymcB4TgvyWu6ZyliaW0tI/otEQ= +github.com/rogpeppe/go-internal v1.14.1/go.mod h1:MaRKkUm5W0goXpeCfT7UZI6fk/L7L7so1lCWt35ZSgc= +github.com/rs/xid v1.2.1 h1:mhH9Nq+C1fY2l1XIpgxIiUOfNpRBYH1kKcr+qfKgjRc= github.com/rs/xid v1.2.1/go.mod h1:+uKXf+4Djp6Md1KODXJxgGQPKngRmWyn10oCKFzNHOQ= github.com/rs/zerolog v1.13.0/go.mod h1:YbFCdg8HfsridGWAh22vktObvhZbQsZXe4/zB0OKkWU= +github.com/rs/zerolog v1.15.0 h1:uPRuwkWF4J6fGsJ2R0Gn2jB1EQiav9k3S6CSdygQJXY= github.com/rs/zerolog v1.15.0/go.mod h1:xYTKnLHcpfU2225ny5qZjxnj9NvkumZYjJHlAThCjNc= +github.com/russross/blackfriday v1.6.0 h1:KqfZb0pUVN2lYqZUYRddxF4OR8ZMURnJIG5Y3VRLtww= +github.com/russross/blackfriday v1.6.0/go.mod h1:ti0ldHuxg49ri4ksnFxlkCfN+hvslNlmVHqNRXXJNAY= github.com/russross/blackfriday/v2 v2.0.1/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= github.com/russross/blackfriday/v2 v2.1.0 h1:JIOH55/0cWyOuilr9/qlrm0BSXldqnqwMsf35Ld67mk= github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= github.com/sagikazarmark/locafero v0.11.0 h1:1iurJgmM9G3PA/I+wWYIOw/5SyBtxapeHDcg+AAIFXc= github.com/sagikazarmark/locafero v0.11.0/go.mod h1:nVIGvgyzw595SUSUE6tvCp3YYTeHs15MvlmU87WwIik= +github.com/santhosh-tekuri/jsonschema/v5 v5.3.1 h1:lZUw3E0/J3roVtGQ+SCrUrg3ON6NgVqpn3+iol9aGu4= +github.com/santhosh-tekuri/jsonschema/v5 v5.3.1/go.mod h1:uToXkOrWAZ6/Oc07xWQrPOhJotwFIyu2bBVN41fcDUY= +github.com/satori/go.uuid v1.2.0 h1:0uYX9dsZ2yD7q2RtLRtPSdGDWzjeM3TbMJP9utgA0ww= github.com/satori/go.uuid v1.2.0/go.mod h1:dA0hQrYB0VpLJoorglMZABFdXlWrHn1NEOzdhQKdks0= github.com/schollz/progressbar/v3 v3.19.0 h1:Ea18xuIRQXLAUidVDox3AbwfUhD0/1IvohyTutOIFoc= github.com/schollz/progressbar/v3 v3.19.0/go.mod h1:IsO3lpbaGuzh8zIMzgY3+J8l4C8GjO0Y9S69eFvNsec= github.com/shopspring/decimal v0.0.0-20180709203117-cd690d0c9e24/go.mod h1:M+9NzErvs504Cn4c5DxATwIqPbtswREoFCre64PpcG4= github.com/shopspring/decimal v1.2.0/go.mod h1:DKyhrW/HYNuLGql+MJL6WCR6knT2jwCFRcu2hWCYk4o= github.com/shopspring/decimal v1.3.1/go.mod h1:DKyhrW/HYNuLGql+MJL6WCR6knT2jwCFRcu2hWCYk4o= +github.com/shopspring/decimal v1.4.0 h1:bxl37RwXBklmTi0C79JfXCEBD1cqqHt0bbgBAGFp81k= +github.com/shopspring/decimal v1.4.0/go.mod h1:gawqmDU56v4yIKSwfBSFip1HdCCXN8/+DMd9qYNcwME= +github.com/shurcooL/sanitized_anchor_name v1.0.0 h1:PdmoCO6wvbs+7yrJyMORt4/BmY5IYyJwS/kOiWx8mHo= github.com/shurcooL/sanitized_anchor_name v1.0.0/go.mod h1:1NzhyTcUVG4SuEtjjoZeVRXNmyL/1OwPU0+IJeTBvfc= github.com/sirupsen/logrus v1.4.1/go.mod h1:ni0Sbl8bgC9z8RoU9G6nDWqqs/fq4eDPysMBDgk/93Q= github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE= +github.com/sirupsen/logrus v1.9.3 h1:dueUQJ1C2q9oE3F7wvmSGAaVtTmUizReu6fjN8uqzbQ= +github.com/sirupsen/logrus v1.9.3/go.mod h1:naHLuLoDiP4jHNo9R0sCBMtWGeIprob74mVsIT4qYEQ= github.com/sony/gobreaker v1.0.0 h1:feX5fGGXSl3dYd4aHZItw+FpHLvvoaqkawKjVNiFMNQ= github.com/sony/gobreaker v1.0.0/go.mod h1:ZKptC7FHNvhBz7dN2LGjPVBz2sZJmc0/PkyDJOjmxWY= github.com/sourcegraph/conc v0.3.1-0.20240121214520-5f936abd7ae8 h1:+jumHNA0Wrelhe64i8F6HNlS8pkoyMv5sreGx2Ry5Rw= @@ -469,6 +612,8 @@ github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+ github.com/stretchr/objx v0.2.0/go.mod h1:qt09Ya8vawLte6SNmTgCsAVtYtaKzEcn8ATUoHMkEqE= github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw= github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo= +github.com/stretchr/objx v0.5.2 h1:xuMeJ0Sdp5ZMRXx/aWO6RZxdr3beISkG5/G/aIRr3pY= +github.com/stretchr/objx v0.5.2/go.mod h1:FRsXN1f5AsAjCGJKqEizvkpNtU+EGNCLh3NxZ/8L+MA= github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4= @@ -491,37 +636,69 @@ github.com/tj/assert v0.0.3 h1:Df/BlaZ20mq6kuai7f5z2TvPFiwC3xaWJSDQNiIS3Rk= github.com/tj/assert v0.0.3/go.mod h1:Ne6X72Q+TB1AteidzQncjw9PabbMp4PBMZ1k+vd1Pvk= github.com/tkuchiki/go-timezone v0.2.3 h1:D3TVdIPrFsu9lxGxqNX2wsZwn1MZtTqTW0mdevMozHc= github.com/tkuchiki/go-timezone v0.2.3/go.mod h1:oFweWxYl35C/s7HMVZXiA19Jr9Y0qJHMaG/J2TES4LY= +github.com/twitchyliquid64/golang-asm v0.15.1 h1:SU5vSMR7hnwNxj24w34ZyCi/FmDZTkS4MhqMhdFk5YI= +github.com/twitchyliquid64/golang-asm v0.15.1/go.mod h1:a1lVb/DtPvCB8fslRZhAngC2+aY1QWCk3Cedj/Gdt08= +github.com/ugorji/go/codec v1.2.9 h1:rmenucSohSTiyL09Y+l2OCk+FrMxGMzho2+tjr5ticU= +github.com/ugorji/go/codec v1.2.9/go.mod h1:UNopzCgEMSXjBc6AOMqYvWC1ktqTAfzJZUZgYf6w6lg= github.com/ulule/limiter/v3 v3.11.2 h1:P4yOrxoEMJbOTfRJR2OzjL90oflzYPPmWg+dvwN2tHA= github.com/ulule/limiter/v3 v3.11.2/go.mod h1:QG5GnFOCV+k7lrL5Y8kgEeeflPH3+Cviqlqa8SVSQxI= github.com/urfave/cli/v2 v2.3.0 h1:qph92Y649prgesehzOrQjdWyxFOp/QVM+6imKHad91M= github.com/urfave/cli/v2 v2.3.0/go.mod h1:LJmUH05zAU44vOAcrfzZQKsZbVcdbOG8rtL3/XcUArI= +github.com/valyala/bytebufferpool v1.0.0 h1:GqA5TC/0021Y/b9FG4Oi9Mr3q7XYx6KllzawFIhcdPw= +github.com/valyala/bytebufferpool v1.0.0/go.mod h1:6bBcMArwyJ5K/AmCkWv1jt77kVWyCJ6HpOuEn7z0Csc= +github.com/valyala/fasthttp v1.47.0 h1:y7moDoxYzMooFpT5aHgNgVOQDrS3qlkfiP9mDtGGK9c= +github.com/valyala/fasthttp v1.47.0/go.mod h1:k2zXd82h/7UZc3VOdJ2WaUqt1uZ/XpXAfE9i+HBC3lA= github.com/wneessen/go-mail v0.7.2 h1:xxPnhZ6IZLSgxShebmZ6DPKh1b6OJcoHfzy7UjOkzS8= github.com/wneessen/go-mail v0.7.2/go.mod h1:+TkW6QP3EVkgTEqHtVmnAE/1MRhmzb8Y9/W3pweuS+k= +github.com/xhit/go-str2duration/v2 v2.1.0 h1:lxklc02Drh6ynqX+DdPyp5pCKLUQpRT8bp8Ydu2Bstc= +github.com/xhit/go-str2duration/v2 v2.1.0/go.mod h1:ohY8p+0f07DiV6Em5LKB0s2YpLtXVyJfNt1+BlmyAsU= github.com/yosssi/gohtml v0.0.0-20201013000340-ee4748c638f4 h1:0sw0nJM544SpsihWx1bkXdYLQDlzRflMgFJQ4Yih9ts= github.com/yosssi/gohtml v0.0.0-20201013000340-ee4748c638f4/go.mod h1:+ccdNT0xMY1dtc5XBxumbYfOUhmduiGudqaDgD2rVRE= github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY= github.com/yuin/goldmark v1.7.16 h1:n+CJdUxaFMiDUNnWC3dMWCIQJSkxH4uz3ZwQBkAlVNE= github.com/yuin/goldmark v1.7.16/go.mod h1:ip/1k0VRfGynBgxOz0yCqHrbZXhcjxyuS66Brc7iBKg= +github.com/zenazn/goji v0.9.0 h1:RSQQAbXGArQ0dIDEq+PI6WqN6if+5KHu6x2Cx/GXLTQ= github.com/zenazn/goji v0.9.0/go.mod h1:7S9M489iMyHBNxwZnk9/EHS098H4/F6TATF2mIxtB1Q= +github.com/ziutek/mymysql v1.5.4 h1:GB0qdRGsTwQSBVYuVShFBKaXSnSnYYC2d9knnE1LHFs= github.com/ziutek/mymysql v1.5.4/go.mod h1:LMSpPZ6DbqWFxNCHW77HeMg9I646SAhApZ/wKdgO/C0= +go.opentelemetry.io/auto/sdk v1.2.1 h1:jXsnJ4Lmnqd11kwkBV2LgLoFMZKizbCi5fNZ/ipaZ64= +go.opentelemetry.io/auto/sdk v1.2.1/go.mod h1:KRTj+aOaElaLi+wW1kO/DZRXwkF4C5xPbEe3ZiIhN7Y= +go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.65.0 h1:7iP2uCb7sGddAr30RRS6xjKy7AZ2JtTOPA3oolgVSw8= +go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.65.0/go.mod h1:c7hN3ddxs/z6q9xwvfLPk+UHlWRQyaeR1LdgfL/66l0= +go.opentelemetry.io/otel v1.40.0 h1:oA5YeOcpRTXq6NN7frwmwFR0Cn3RhTVZvXsP4duvCms= +go.opentelemetry.io/otel v1.40.0/go.mod h1:IMb+uXZUKkMXdPddhwAHm6UfOwJyh4ct1ybIlV14J0g= +go.opentelemetry.io/otel/metric v1.40.0 h1:rcZe317KPftE2rstWIBitCdVp89A2HqjkxR3c11+p9g= +go.opentelemetry.io/otel/metric v1.40.0/go.mod h1:ib/crwQH7N3r5kfiBZQbwrTge743UDc7DTFVZrrXnqc= +go.opentelemetry.io/otel/sdk v1.40.0 h1:KHW/jUzgo6wsPh9At46+h4upjtccTmuZCFAc9OJ71f8= +go.opentelemetry.io/otel/sdk v1.40.0/go.mod h1:Ph7EFdYvxq72Y8Li9q8KebuYUr2KoeyHx0DRMKrYBUE= +go.opentelemetry.io/otel/sdk/metric v1.40.0 h1:mtmdVqgQkeRxHgRv4qhyJduP3fYJRMX4AtAlbuWdCYw= +go.opentelemetry.io/otel/sdk/metric v1.40.0/go.mod h1:4Z2bGMf0KSK3uRjlczMOeMhKU2rhUqdWNoKcYrtcBPg= +go.opentelemetry.io/otel/trace v1.40.0 h1:WA4etStDttCSYuhwvEa8OP8I5EWu24lkOzp+ZYblVjw= +go.opentelemetry.io/otel/trace v1.40.0/go.mod h1:zeAhriXecNGP/s2SEG3+Y8X9ujcJOTqQ5RgdEJcawiA= go.uber.org/atomic v1.3.2/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE= go.uber.org/atomic v1.4.0/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE= go.uber.org/atomic v1.5.0/go.mod h1:sABNBOSYdrvTF6hTgEIbc7YasKWGhgEQZyfxyTvoXHQ= +go.uber.org/atomic v1.6.0 h1:Ezj3JGmsOnG1MoRWQkPBsKLe9DwWD9QeXzTRzzldNVk= go.uber.org/atomic v1.6.0/go.mod h1:sABNBOSYdrvTF6hTgEIbc7YasKWGhgEQZyfxyTvoXHQ= go.uber.org/goleak v1.3.0 h1:2K3zAYmnTNqV73imy9J1T3WC+gmCePx2hEGkimedGto= go.uber.org/goleak v1.3.0/go.mod h1:CoHD4mav9JJNrW/WLlf7HGZPjdw8EucARQHekz1X6bE= go.uber.org/multierr v1.1.0/go.mod h1:wR5kodmAFQ0UK8QlbwjlSNy0Z68gJhDJUG5sjR94q/0= go.uber.org/multierr v1.3.0/go.mod h1:VgVr7evmIr6uPjLBxg28wmKNXyqE9akIJ5XnfpiKl+4= +go.uber.org/multierr v1.5.0 h1:KCa4XfM8CWFCpxXRGok+Q0SS/0XBhMDbHHGABQLvD2A= go.uber.org/multierr v1.5.0/go.mod h1:FeouvMocqHpRaaGuG9EjoKcStLC43Zu/fmqdUMPcKYU= +go.uber.org/tools v0.0.0-20190618225709-2cfd321de3ee h1:0mgffUl7nfd+FpvXMVz4IDEaUSmT1ysygQC7qYo7sG4= go.uber.org/tools v0.0.0-20190618225709-2cfd321de3ee/go.mod h1:vJERXedbb3MVM5f9Ejo0C68/HhF8uaILCdgjnY+goOA= go.uber.org/zap v1.9.1/go.mod h1:vwi/ZaCAaUcBkycHslxD9B2zi4UTXhF60s6SWpuDF0Q= go.uber.org/zap v1.10.0/go.mod h1:vwi/ZaCAaUcBkycHslxD9B2zi4UTXhF60s6SWpuDF0Q= +go.uber.org/zap v1.13.0 h1:nR6NoDBgAf67s68NhaXbsojM+2gxp3S1hWkHDl27pVU= go.uber.org/zap v1.13.0/go.mod h1:zwrFLgMcdUuIBviXEYEH1YKNaOBnKXsx2IPda5bBwHM= go.yaml.in/yaml/v2 v2.4.2 h1:DzmwEr2rDGHl7lsFgAHxmNz/1NlQ7xLIrlN2h5d1eGI= go.yaml.in/yaml/v2 v2.4.2/go.mod h1:081UH+NErpNdqlCXm3TtEran0rJZGxAYx9hb/ELlsPU= go.yaml.in/yaml/v3 v3.0.4 h1:tfq32ie2Jv2UxXFdLJdh3jXuOzWiL1fo0bu/FbuKpbc= go.yaml.in/yaml/v3 v3.0.4/go.mod h1:DhzuOOF2ATzADvBadXxruRBLzYTpT36CKvDb3+aBEFg= +golang.org/x/arch v0.0.0-20210923205945-b76863e36670 h1:18EFjUmQOcUvxNYSkA6jO9VAiXCnxFY6NyDX0bHDmkU= +golang.org/x/arch v0.0.0-20210923205945-b76863e36670/go.mod h1:5om86z9Hs0C8fWVUuoMHwpExlXzs5Tkyp9hOrfG7pp8= golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= golang.org/x/crypto v0.0.0-20190411191339-88737f569e3a/go.mod h1:WFFai1msRO1wXaEeE5yQxYXgSfI8pQAWXbQop6sCtWE= golang.org/x/crypto v0.0.0-20190510104115-cbcb75029529/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= @@ -540,6 +717,7 @@ golang.org/x/crypto v0.47.0/go.mod h1:ff3Y9VzzKbwSSEzWqJsJVBnWmRwRSHt/6Op5n9bQc4 golang.org/x/image v0.0.0-20191009234506-e7c1f5e7dbb8/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0= golang.org/x/image v0.35.0 h1:LKjiHdgMtO8z7Fh18nGY6KDcoEtVfsgLDPeLyguqb7I= golang.org/x/image v0.35.0/go.mod h1:MwPLTVgvxSASsxdLzKrl8BRFuyqMyGhLwmC+TO1Sybk= +golang.org/x/lint v0.0.0-20190930215403-16217165b5de h1:5hukYrvBGR8/eNkX5mdUezrA6JiaEZDtJb9Ei+1LlBs= golang.org/x/lint v0.0.0-20190930215403-16217165b5de/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= golang.org/x/mod v0.0.0-20190513183733-4bf6d317e70e/go.mod h1:mXi4GBBbnImb6dmsKGUJ2LatrhH/nqhxcFungHvyanc= golang.org/x/mod v0.1.1-0.20191105210325-c90efee705ee/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg= @@ -592,6 +770,7 @@ golang.org/x/sys v0.0.0-20210112080510-489259a85091/go.mod h1:h1NjWce9XRLGQEsW7w golang.org/x/sys v0.0.0-20210420072515-93ed5bcd2bfe/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20210616094352-59db8d763f22/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220310020820-b874c991c1a5/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= @@ -600,12 +779,18 @@ golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.40.0 h1:DBZZqJ2Rkml6QMQsZywtnjnnGvHza6BTfYFWY9kjEWQ= golang.org/x/sys v0.40.0/go.mod h1:OgkHotnGiDImocRcuBABYBEXf8A9a87e/uXjp9XT3ks= +golang.org/x/sys v0.41.0 h1:Ivj+2Cp/ylzLiEU89QhWblYnOE9zerudt9Ftecq2C6k= +golang.org/x/sys v0.41.0/go.mod h1:OgkHotnGiDImocRcuBABYBEXf8A9a87e/uXjp9XT3ks= +golang.org/x/telemetry v0.0.0-20251203150158-8fff8a5912fc h1:bH6xUXay0AIFMElXG2rQ4uiE+7ncwtiOdPfYK1NK2XA= +golang.org/x/telemetry v0.0.0-20251203150158-8fff8a5912fc/go.mod h1:hKdjCMrbv9skySur+Nek8Hd0uJ0GuxJIoIX2payrIdQ= golang.org/x/term v0.0.0-20201117132131-f5c789dd3221/go.mod h1:Nr5EML6q2oocZ2LXRh80K7BxOlk5/8JxuGnuhpl+muw= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= golang.org/x/term v0.5.0/go.mod h1:jMB1sMXY+tzblOD4FWmEbocvup2/aLOaQEp7JmGp78k= golang.org/x/term v0.39.0 h1:RclSuaJf32jOqZz74CkPA9qFuVTX7vhLlpfj/IGWlqY= golang.org/x/term v0.39.0/go.mod h1:yxzUCTP/U+FzoxfdKmLaA0RV1WgE0VY7hXBwKtY/4ww= +golang.org/x/term v0.40.0 h1:36e4zGLqU4yhjlmxEaagx2KuYbJq3EwY8K943ZsHcvg= +golang.org/x/term v0.40.0/go.mod h1:w2P8uVp06p2iyKKuvXIm7N/y0UCRt3UfJTfZ7oOpglM= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk= golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= @@ -637,7 +822,12 @@ golang.org/x/xerrors v0.0.0-20190513163551-3ee3066db522/go.mod h1:I/5z698sn9Ka8T golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1 h1:go1bK/D/BFZV2I8cIQd1NKEZ+0owSTG1fDTci4IqFcE= golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +google.golang.org/genproto/googleapis/rpc v0.0.0-20240903143218-8af14fe29dc1 h1:pPJltXNxVzT4pK9yD8vR9X75DaWYYmLGMsEvBfFQZzQ= +google.golang.org/genproto/googleapis/rpc v0.0.0-20240903143218-8af14fe29dc1/go.mod h1:UqMtugtsSgubUsoxbuAoiCXvqvErP7Gf0so0mK9tHxU= +google.golang.org/grpc v1.67.0 h1:IdH9y6PF5MPSdAntIcpjQ+tXO41pcQsfZV2RxtQgVcw= +google.golang.org/grpc v1.67.0/go.mod h1:1gLDyUQU7CTLJI90u3nXZ9ekeghjeM7pTDZlqFNg2AA= google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8= google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0= google.golang.org/protobuf v0.0.0-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQJ+fmap5saPgwCLgHXTUD7jkjRqWcaiX5VyM= @@ -655,8 +845,11 @@ gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntN gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q= gopkg.in/d4l3k/messagediff.v1 v1.2.1 h1:70AthpjunwzUiarMHyED52mj9UwtAnE89l1Gmrt3EU0= gopkg.in/d4l3k/messagediff.v1 v1.2.1/go.mod h1:EUzikiKadqXWcD1AzJLagx0j/BeeWGtn++04Xniyg44= +gopkg.in/errgo.v2 v2.1.0 h1:0vLT13EuvQ0hNvakwLuFZ/jYrLp5F3kcWHXdRggjCE8= gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI= +gopkg.in/fsnotify.v1 v1.4.7 h1:xOHLXZwVvI9hhs+cLKq5+I5onOuwQLhQwiu63xxlHs4= gopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys= +gopkg.in/inconshreveable/log15.v2 v2.0.0-20180818164646-67afb5ed74ec h1:RlWgLqCMMIYYEVcAR5MDsuHlVkaIPDAF+5Dehzg8L5A= gopkg.in/inconshreveable/log15.v2 v2.0.0-20180818164646-67afb5ed74ec/go.mod h1:aPpfJ7XW+gOuirDoZ8gHhLh3kZ1B08FtV2bbmy7Jv3s= gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7 h1:uRGJdciOHaEIrze2W8Q3AKkepLTh2hOroT7a+7czfdQ= gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWDmTeBkI65Dw0HsyUHuEVlX15mw= @@ -674,6 +867,9 @@ gopkg.in/yaml.v3 v3.0.0-20200615113413-eeeca48fe776/go.mod h1:K4uyk7z7BCEPqu6E+C gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= +gotest.tools/v3 v3.5.2 h1:7koQfIKdy+I8UTetycgUqXWSDwpgv193Ka+qRsmBY8Q= +gotest.tools/v3 v3.5.2/go.mod h1:LtdLGcnqToBH83WByAAi/wiwSFCArdFIUV/xxN4pcjA= +honnef.co/go/tools v0.0.1-2019.2.3 h1:3JgtbtFHMiCmsznwGVTUWbgGov+pVqnlf1dEJTNAXeM= honnef.co/go/tools v0.0.1-2019.2.3/go.mod h1:a3bituU0lyd329TUQxRnasdCoJDkEUEAqEt0JzvZhAg= lukechampine.com/uint128 v1.1.1/go.mod h1:c4eWIwlEGaxC/+H1VguhU4PHXNWDCDMUlWdIWl2j1gk= lukechampine.com/uint128 v1.2.0 h1:mBi/5l91vocEN8otkC5bDLhi2KdCticRiwbdB0O+rjI= @@ -687,7 +883,9 @@ modernc.org/ccgo/v3 v3.0.0-20220910160915-348f15de615a/go.mod h1:8p47QxPkdugex9J modernc.org/ccgo/v3 v3.16.13-0.20221017192402-261537637ce8/go.mod h1:fUB3Vn0nVPReA+7IG7yZDfjv1TMWjhQP8gCxrFAtL5g= modernc.org/ccgo/v3 v3.16.13 h1:Mkgdzl46i5F/CNR/Kj80Ri59hC8TKAhZrYSaqvkwzUw= modernc.org/ccgo/v3 v3.16.13/go.mod h1:2Quk+5YgpImhPjv2Qsob1DnZ/4som1lJTodubIcoUkY= +modernc.org/ccorpus v1.11.6 h1:J16RXiiqiCgua6+ZvQot4yUuUy8zxgqbqEEUuGPlISk= modernc.org/ccorpus v1.11.6/go.mod h1:2gEUTrWqdpH2pXsmTM1ZkjeSrUWDpjMu2T6m29L/ErQ= +modernc.org/httpfs v1.0.6 h1:AAgIpFZRXuYnkjftxTAZwMIiwEqAfk8aVB2/oA6nAeM= modernc.org/httpfs v1.0.6/go.mod h1:7dosgurJGp0sPaRanU53W4xZYKh14wfzX420oZADeHM= modernc.org/libc v1.17.4/go.mod h1:WNg2ZH56rDEwdropAJeZPQkXmDwh+JCA1s/htl6r2fA= modernc.org/libc v1.18.0/go.mod h1:vj6zehR5bfc98ipowQOM2nIDUZnVew/wNC/2tOGS+q0= @@ -712,17 +910,23 @@ modernc.org/sqlite v1.20.4/go.mod h1:zKcGyrICaxNTMEHSr1HQ2GUraP0j+845GYw37+EyT6A modernc.org/strutil v1.1.3/go.mod h1:MEHNA7PdEnEwLvspRMtWTNnp2nnyvMfkimT1NKNAGbw= modernc.org/strutil v1.2.0 h1:agBi9dp1I+eOnxXeiZawM8F4LawKv4NzGWSaLfyeNZA= modernc.org/strutil v1.2.0/go.mod h1:/mdcBmfOibveCTBxUl5B5l6W+TTH1FXPLHZE6bTosX0= +modernc.org/tcl v1.15.0 h1:oY+JeD11qVVSgVvodMJsu7Edf8tr5E/7tuhF5cNYz34= modernc.org/tcl v1.15.0/go.mod h1:xRoGotBZ6dU+Zo2tca+2EqVEeMmOUBzHnhIwq4YrVnE= modernc.org/token v1.0.1/go.mod h1:UGzOrNV1mAFSEB63lOFHIpNRUVMvYTc6yu1SMY/XTDM= modernc.org/token v1.1.0 h1:Xl7Ap9dKaEs5kLoOQeQmPWevfnk/DM5qcLcYlA8ys6Y= modernc.org/token v1.1.0/go.mod h1:UGzOrNV1mAFSEB63lOFHIpNRUVMvYTc6yu1SMY/XTDM= +modernc.org/z v1.7.0 h1:xkDw/KepgEjeizO2sNco+hqYkU12taxQFqPEmgm1GWE= modernc.org/z v1.7.0/go.mod h1:hVdgNMh8ggTuRG1rGU8x+xGRFfiQUIAw0ZqlPy8+HyQ= mvdan.cc/xurls/v2 v2.6.0 h1:3NTZpeTxYVWNSokW3MKeyVkz/j7uYXYiMtXRUfmjbgI= mvdan.cc/xurls/v2 v2.6.0/go.mod h1:bCvEZ1XvdA6wDnxY7jPPjEmigDtvtvPXAD/Exa9IMSk= +pgregory.net/rapid v1.2.0 h1:keKAYRcjm+e1F0oAuU5F5+YPAWcyxNNRK2wud503Gnk= +pgregory.net/rapid v1.2.0/go.mod h1:PY5XlDGj0+V1FCq0o192FdRhpKHGTRIWBgqjDBTrq04= sigs.k8s.io/yaml v1.3.0 h1:a2VclLzOGrwOHDiV8EfBGhvjHvP46CtW5j6POvhYGGo= sigs.k8s.io/yaml v1.3.0/go.mod h1:GeOyir5tyXNByN85N/dRIT9es5UQNerPYEKK56eTBm8= src.techknowlogick.com/xgo v1.8.1-0.20241105013731-313dedef864f h1:Dy7qQ31o3z4EV+0ISDH1IldkPxzubOAvV7DW+9HnbNg= src.techknowlogick.com/xgo v1.8.1-0.20241105013731-313dedef864f/go.mod h1:31CE1YKtDOrKTk9PSnjTpe6YbO6W/0LTYZ1VskL09oU= +src.techknowlogick.com/xgo v1.9.0 h1:IlAoK9uRnvniCjX/Mruydonm3XtAe/dgjSV2kBww370= +src.techknowlogick.com/xgo v1.9.0/go.mod h1:gMKej7rx5ksiGKwmKpVA4keweoAoFQyRC0rAZKO0vlw= src.techknowlogick.com/xormigrate v1.7.1 h1:RKGLLUAqJ+zO8iZ7eOc7oLH7f0cs2gfXSZSvBRBHnlY= src.techknowlogick.com/xormigrate v1.7.1/go.mod h1:YGNBdj8prENlySwIKmfoEXp7ILGjAltyKFXD0qLgD7U= xorm.io/builder v0.3.11-0.20220531020008-1bd24a7dc978/go.mod h1:aUW0S9eb9VCaPohFCH3j7czOx1PMW3i1HrSzbLYGBSE= diff --git a/tools.go b/tools.go deleted file mode 100644 index 91bc0e331..000000000 --- a/tools.go +++ /dev/null @@ -1,29 +0,0 @@ -// Vikunja is a to-do list application to facilitate your life. -// Copyright 2018-present Vikunja and contributors. All rights reserved. -// -// This program is free software: you can redistribute it and/or modify -// it under the terms of the GNU Affero General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. -// -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU Affero General Public License for more details. -// -// You should have received a copy of the GNU Affero General Public License -// along with this program. If not, see . - -//go:build tools - -package tools - -// This file is needed for go mod to recognize the tools we use. - -import ( - _ "github.com/cweill/gotests" - _ "github.com/swaggo/swag/cmd/swag" - _ "src.techknowlogick.com/xgo" - - _ "github.com/magefile/mage" -) From bc583b2efb73b153c286fbb97255edecfd88c48e Mon Sep 17 00:00:00 2001 From: "Frederick [Bot]" Date: Sat, 7 Mar 2026 01:09:03 +0000 Subject: [PATCH 030/142] chore(i18n): update translations via Crowdin --- frontend/src/i18n/lang/fi-FI.json | 1 + 1 file changed, 1 insertion(+) diff --git a/frontend/src/i18n/lang/fi-FI.json b/frontend/src/i18n/lang/fi-FI.json index 3035a91f8..d124ecc89 100644 --- a/frontend/src/i18n/lang/fi-FI.json +++ b/frontend/src/i18n/lang/fi-FI.json @@ -91,6 +91,7 @@ "discoverableByName": "Salli muiden käyttäjien lisätä minut jäseneksi tiimeihin tai projekteihin, kun he etsivät nimeäni", "discoverableByEmail": "Salli muiden käyttäjien lisätä minut jäseneksi tiimeihin tai projekteihin, kun he etsivät koko sähköpostiani", "playSoundWhenDone": "Toista ääni, kun tehtävä merkitään valmiiksi", + "alwaysShowBucketTaskCount": "Näytä aina tehtävien lukumäärä Kanban sarakkeissa", "weekStart": "Viikon ensimmäinen päivä", "weekStartSunday": "Sunnuntai", "weekStartMonday": "Maanantai", From 52e47c732feab2a1f7ee329f5ccf3c0668096ae2 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Sat, 7 Mar 2026 02:06:21 +0000 Subject: [PATCH 031/142] chore(deps): update dependency eslint to v9.39.4 --- frontend/package.json | 2 +- frontend/pnpm-lock.yaml | 152 ++++++++++++++++++++-------------------- 2 files changed, 77 insertions(+), 77 deletions(-) diff --git a/frontend/package.json b/frontend/package.json index 0147eda44..ce5d747a7 100644 --- a/frontend/package.json +++ b/frontend/package.json @@ -128,7 +128,7 @@ "caniuse-lite": "1.0.30001777", "csstype": "3.2.3", "esbuild": "0.27.3", - "eslint": "9.39.3", + "eslint": "9.39.4", "eslint-plugin-depend": "1.5.0", "eslint-plugin-vue": "10.8.0", "happy-dom": "20.8.3", diff --git a/frontend/pnpm-lock.yaml b/frontend/pnpm-lock.yaml index c5a7ec2db..9407ce315 100644 --- a/frontend/pnpm-lock.yaml +++ b/frontend/pnpm-lock.yaml @@ -31,7 +31,7 @@ importers: version: 3.1.3(@fortawesome/fontawesome-svg-core@7.1.0)(vue@3.5.27(typescript@5.9.3)) '@intlify/unplugin-vue-i18n': specifier: 11.0.3 - version: 11.0.3(@vue/compiler-dom@3.5.27)(eslint@9.39.3(jiti@2.4.2))(rollup@4.59.0)(typescript@5.9.3)(vue-i18n@11.2.8(vue@3.5.27(typescript@5.9.3)))(vue@3.5.27(typescript@5.9.3)) + version: 11.0.3(@vue/compiler-dom@3.5.27)(eslint@9.39.4(jiti@2.4.2))(rollup@4.59.0)(typescript@5.9.3)(vue-i18n@11.2.8(vue@3.5.27(typescript@5.9.3)))(vue@3.5.27(typescript@5.9.3)) '@kyvg/vue3-notification': specifier: 3.4.2 version: 3.4.2(vue@3.5.27(typescript@5.9.3)) @@ -206,16 +206,16 @@ importers: version: 1.15.9 '@typescript-eslint/eslint-plugin': specifier: 8.56.1 - version: 8.56.1(@typescript-eslint/parser@8.56.1(eslint@9.39.3(jiti@2.4.2))(typescript@5.9.3))(eslint@9.39.3(jiti@2.4.2))(typescript@5.9.3) + version: 8.56.1(@typescript-eslint/parser@8.56.1(eslint@9.39.4(jiti@2.4.2))(typescript@5.9.3))(eslint@9.39.4(jiti@2.4.2))(typescript@5.9.3) '@typescript-eslint/parser': specifier: 8.56.1 - version: 8.56.1(eslint@9.39.3(jiti@2.4.2))(typescript@5.9.3) + version: 8.56.1(eslint@9.39.4(jiti@2.4.2))(typescript@5.9.3) '@vitejs/plugin-vue': specifier: 6.0.4 version: 6.0.4(vite@7.3.1(@types/node@24.12.0)(jiti@2.4.2)(lightningcss@1.31.1)(sass-embedded@1.97.3)(sass@1.97.3)(terser@5.31.6)(yaml@2.5.0))(vue@3.5.27(typescript@5.9.3)) '@vue/eslint-config-typescript': specifier: 14.7.0 - version: 14.7.0(eslint-plugin-vue@10.8.0(@typescript-eslint/parser@8.56.1(eslint@9.39.3(jiti@2.4.2))(typescript@5.9.3))(eslint@9.39.3(jiti@2.4.2))(vue-eslint-parser@10.4.0(eslint@9.39.3(jiti@2.4.2))))(eslint@9.39.3(jiti@2.4.2))(typescript@5.9.3) + version: 14.7.0(eslint-plugin-vue@10.8.0(@typescript-eslint/parser@8.56.1(eslint@9.39.4(jiti@2.4.2))(typescript@5.9.3))(eslint@9.39.4(jiti@2.4.2))(vue-eslint-parser@10.4.0(eslint@9.39.4(jiti@2.4.2))))(eslint@9.39.4(jiti@2.4.2))(typescript@5.9.3) '@vue/test-utils': specifier: 2.4.6 version: 2.4.6 @@ -241,14 +241,14 @@ importers: specifier: 0.27.3 version: 0.27.3 eslint: - specifier: 9.39.3 - version: 9.39.3(jiti@2.4.2) + specifier: 9.39.4 + version: 9.39.4(jiti@2.4.2) eslint-plugin-depend: specifier: 1.5.0 - version: 1.5.0(eslint@9.39.3(jiti@2.4.2)) + version: 1.5.0(eslint@9.39.4(jiti@2.4.2)) eslint-plugin-vue: specifier: 10.8.0 - version: 10.8.0(@typescript-eslint/parser@8.56.1(eslint@9.39.3(jiti@2.4.2))(typescript@5.9.3))(eslint@9.39.3(jiti@2.4.2))(vue-eslint-parser@10.4.0(eslint@9.39.3(jiti@2.4.2))) + version: 10.8.0(@typescript-eslint/parser@8.56.1(eslint@9.39.4(jiti@2.4.2))(typescript@5.9.3))(eslint@9.39.4(jiti@2.4.2))(vue-eslint-parser@10.4.0(eslint@9.39.4(jiti@2.4.2))) happy-dom: specifier: 20.8.3 version: 20.8.3 @@ -1582,8 +1582,8 @@ packages: resolution: {integrity: sha512-EriSTlt5OC9/7SXkRSCAhfSxxoSUgBm33OH+IkwbdpgoqsSsUg7y3uh+IICI/Qg4BBWr3U2i39RpmycbxMq4ew==} engines: {node: ^12.0.0 || ^14.0.0 || >=16.0.0} - '@eslint/config-array@0.21.1': - resolution: {integrity: sha512-aw1gNayWpdI/jSYVgzN5pL0cfzU02GT3NBpeT/DXbx1/1x7ZKxFPd9bwrzygx/qiwIQiJ1sw/zD8qY/kRvlGHA==} + '@eslint/config-array@0.21.2': + resolution: {integrity: sha512-nJl2KGTlrf9GjLimgIru+V/mzgSK0ABCDQRvxw5BjURL7WfH5uoWmizbH7QB6MmnMBd8cIC9uceWnezL1VZWWw==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} '@eslint/config-helpers@0.4.2': @@ -1594,12 +1594,12 @@ packages: resolution: {integrity: sha512-yL/sLrpmtDaFEiUj1osRP4TI2MDz1AddJL+jZ7KSqvBuliN4xqYY54IfdN8qD8Toa6g1iloph1fxQNkjOxrrpQ==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} - '@eslint/eslintrc@3.3.1': - resolution: {integrity: sha512-gtF186CXhIl1p4pJNGZw8Yc6RlshoePRvE0X91oPGb3vZ8pM3qOS9W9NGPat9LziaBV7XrJWGylNQXkGcnM3IQ==} + '@eslint/eslintrc@3.3.5': + resolution: {integrity: sha512-4IlJx0X0qftVsN5E+/vGujTRIFtwuLbNsVUe7TO6zYPDR1O6nFwvwhIKEKSrl6dZchmYBITazxKoUYOjdtjlRg==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} - '@eslint/js@9.39.3': - resolution: {integrity: sha512-1B1VkCq6FuUNlQvlBYb+1jDu/gV297TIs/OeiaSR9l1H27SVW55ONE1e1Vp16NqP683+xEGzxYtv4XCiDPaQiw==} + '@eslint/js@9.39.4': + resolution: {integrity: sha512-nE7DEIchvtiFTwBw4Lfbu59PG+kCofhjsKaCWzxTpt4lfRjRMqG6uMBzKXuEcyXhOHoUp9riAm7/aWYGhXZ9cw==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} '@eslint/object-schema@2.1.7': @@ -3813,8 +3813,8 @@ packages: resolution: {integrity: sha512-A0XeIi7CXU7nPlfHS9loMYEKxUaONu/hTEzHTGba9Huu94Cq1hPivf+DE5erJozZOky0LfvXAyrV/tcswpLI0Q==} engines: {node: ^20.19.0 || ^22.13.0 || >=24} - eslint@9.39.3: - resolution: {integrity: sha512-VmQ+sifHUbI/IcSopBCF/HO3YiHQx/AVd3UVyYL6weuwW+HvON9VYn5l6Zl1WZzPWXPNZrSQpxwkkZ/VuvJZzg==} + eslint@9.39.4: + resolution: {integrity: sha512-XoMjdBOwe/esVgEvLmNsD3IRHkm7fbKIUGvrleloJXUZgDHig2IPWNniv+GwjyJXzuNqVjlr5+4yVUZjycJwfQ==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} hasBin: true peerDependencies: @@ -8144,19 +8144,19 @@ snapshots: '@esbuild/win32-x64@0.27.3': optional: true - '@eslint-community/eslint-utils@4.9.0(eslint@9.39.3(jiti@2.4.2))': + '@eslint-community/eslint-utils@4.9.0(eslint@9.39.4(jiti@2.4.2))': dependencies: - eslint: 9.39.3(jiti@2.4.2) + eslint: 9.39.4(jiti@2.4.2) eslint-visitor-keys: 3.4.3 - '@eslint-community/eslint-utils@4.9.1(eslint@9.39.3(jiti@2.4.2))': + '@eslint-community/eslint-utils@4.9.1(eslint@9.39.4(jiti@2.4.2))': dependencies: - eslint: 9.39.3(jiti@2.4.2) + eslint: 9.39.4(jiti@2.4.2) eslint-visitor-keys: 3.4.3 '@eslint-community/regexpp@4.12.2': {} - '@eslint/config-array@0.21.1': + '@eslint/config-array@0.21.2': dependencies: '@eslint/object-schema': 2.1.7 debug: 4.4.3 @@ -8172,7 +8172,7 @@ snapshots: dependencies: '@types/json-schema': 7.0.15 - '@eslint/eslintrc@3.3.1': + '@eslint/eslintrc@3.3.5': dependencies: ajv: 6.14.0 debug: 4.4.3 @@ -8186,7 +8186,7 @@ snapshots: transitivePeerDependencies: - supports-color - '@eslint/js@9.39.3': {} + '@eslint/js@9.39.4': {} '@eslint/object-schema@2.1.7': {} @@ -8381,9 +8381,9 @@ snapshots: '@intlify/shared@11.2.8': {} - '@intlify/unplugin-vue-i18n@11.0.3(@vue/compiler-dom@3.5.27)(eslint@9.39.3(jiti@2.4.2))(rollup@4.59.0)(typescript@5.9.3)(vue-i18n@11.2.8(vue@3.5.27(typescript@5.9.3)))(vue@3.5.27(typescript@5.9.3))': + '@intlify/unplugin-vue-i18n@11.0.3(@vue/compiler-dom@3.5.27)(eslint@9.39.4(jiti@2.4.2))(rollup@4.59.0)(typescript@5.9.3)(vue-i18n@11.2.8(vue@3.5.27(typescript@5.9.3)))(vue@3.5.27(typescript@5.9.3))': dependencies: - '@eslint-community/eslint-utils': 4.9.0(eslint@9.39.3(jiti@2.4.2)) + '@eslint-community/eslint-utils': 4.9.0(eslint@9.39.4(jiti@2.4.2)) '@intlify/bundle-utils': 11.0.3(vue-i18n@11.2.8(vue@3.5.27(typescript@5.9.3))) '@intlify/shared': 11.2.2 '@intlify/vue-i18n-extensions': 8.0.0(@intlify/shared@11.2.2)(@vue/compiler-dom@3.5.27)(vue-i18n@11.2.8(vue@3.5.27(typescript@5.9.3)))(vue@3.5.27(typescript@5.9.3)) @@ -9236,15 +9236,15 @@ snapshots: '@types/node': 24.12.0 optional: true - '@typescript-eslint/eslint-plugin@8.56.0(@typescript-eslint/parser@8.56.0(eslint@9.39.3(jiti@2.4.2))(typescript@5.9.3))(eslint@9.39.3(jiti@2.4.2))(typescript@5.9.3)': + '@typescript-eslint/eslint-plugin@8.56.0(@typescript-eslint/parser@8.56.0(eslint@9.39.4(jiti@2.4.2))(typescript@5.9.3))(eslint@9.39.4(jiti@2.4.2))(typescript@5.9.3)': dependencies: '@eslint-community/regexpp': 4.12.2 - '@typescript-eslint/parser': 8.56.0(eslint@9.39.3(jiti@2.4.2))(typescript@5.9.3) + '@typescript-eslint/parser': 8.56.0(eslint@9.39.4(jiti@2.4.2))(typescript@5.9.3) '@typescript-eslint/scope-manager': 8.56.0 - '@typescript-eslint/type-utils': 8.56.0(eslint@9.39.3(jiti@2.4.2))(typescript@5.9.3) - '@typescript-eslint/utils': 8.56.0(eslint@9.39.3(jiti@2.4.2))(typescript@5.9.3) + '@typescript-eslint/type-utils': 8.56.0(eslint@9.39.4(jiti@2.4.2))(typescript@5.9.3) + '@typescript-eslint/utils': 8.56.0(eslint@9.39.4(jiti@2.4.2))(typescript@5.9.3) '@typescript-eslint/visitor-keys': 8.56.0 - eslint: 9.39.3(jiti@2.4.2) + eslint: 9.39.4(jiti@2.4.2) ignore: 7.0.5 natural-compare: 1.4.0 ts-api-utils: 2.4.0(typescript@5.9.3) @@ -9252,15 +9252,15 @@ snapshots: transitivePeerDependencies: - supports-color - '@typescript-eslint/eslint-plugin@8.56.1(@typescript-eslint/parser@8.56.1(eslint@9.39.3(jiti@2.4.2))(typescript@5.9.3))(eslint@9.39.3(jiti@2.4.2))(typescript@5.9.3)': + '@typescript-eslint/eslint-plugin@8.56.1(@typescript-eslint/parser@8.56.1(eslint@9.39.4(jiti@2.4.2))(typescript@5.9.3))(eslint@9.39.4(jiti@2.4.2))(typescript@5.9.3)': dependencies: '@eslint-community/regexpp': 4.12.2 - '@typescript-eslint/parser': 8.56.1(eslint@9.39.3(jiti@2.4.2))(typescript@5.9.3) + '@typescript-eslint/parser': 8.56.1(eslint@9.39.4(jiti@2.4.2))(typescript@5.9.3) '@typescript-eslint/scope-manager': 8.56.1 - '@typescript-eslint/type-utils': 8.56.1(eslint@9.39.3(jiti@2.4.2))(typescript@5.9.3) - '@typescript-eslint/utils': 8.56.1(eslint@9.39.3(jiti@2.4.2))(typescript@5.9.3) + '@typescript-eslint/type-utils': 8.56.1(eslint@9.39.4(jiti@2.4.2))(typescript@5.9.3) + '@typescript-eslint/utils': 8.56.1(eslint@9.39.4(jiti@2.4.2))(typescript@5.9.3) '@typescript-eslint/visitor-keys': 8.56.1 - eslint: 9.39.3(jiti@2.4.2) + eslint: 9.39.4(jiti@2.4.2) ignore: 7.0.5 natural-compare: 1.4.0 ts-api-utils: 2.4.0(typescript@5.9.3) @@ -9268,26 +9268,26 @@ snapshots: transitivePeerDependencies: - supports-color - '@typescript-eslint/parser@8.56.0(eslint@9.39.3(jiti@2.4.2))(typescript@5.9.3)': + '@typescript-eslint/parser@8.56.0(eslint@9.39.4(jiti@2.4.2))(typescript@5.9.3)': dependencies: '@typescript-eslint/scope-manager': 8.56.0 '@typescript-eslint/types': 8.56.0 '@typescript-eslint/typescript-estree': 8.56.0(typescript@5.9.3) '@typescript-eslint/visitor-keys': 8.56.0 debug: 4.4.3 - eslint: 9.39.3(jiti@2.4.2) + eslint: 9.39.4(jiti@2.4.2) typescript: 5.9.3 transitivePeerDependencies: - supports-color - '@typescript-eslint/parser@8.56.1(eslint@9.39.3(jiti@2.4.2))(typescript@5.9.3)': + '@typescript-eslint/parser@8.56.1(eslint@9.39.4(jiti@2.4.2))(typescript@5.9.3)': dependencies: '@typescript-eslint/scope-manager': 8.56.1 '@typescript-eslint/types': 8.56.1 '@typescript-eslint/typescript-estree': 8.56.1(typescript@5.9.3) '@typescript-eslint/visitor-keys': 8.56.1 debug: 4.4.3 - eslint: 9.39.3(jiti@2.4.2) + eslint: 9.39.4(jiti@2.4.2) typescript: 5.9.3 transitivePeerDependencies: - supports-color @@ -9346,25 +9346,25 @@ snapshots: dependencies: typescript: 5.9.3 - '@typescript-eslint/type-utils@8.56.0(eslint@9.39.3(jiti@2.4.2))(typescript@5.9.3)': + '@typescript-eslint/type-utils@8.56.0(eslint@9.39.4(jiti@2.4.2))(typescript@5.9.3)': dependencies: '@typescript-eslint/types': 8.56.0 '@typescript-eslint/typescript-estree': 8.56.0(typescript@5.9.3) - '@typescript-eslint/utils': 8.56.0(eslint@9.39.3(jiti@2.4.2))(typescript@5.9.3) + '@typescript-eslint/utils': 8.56.0(eslint@9.39.4(jiti@2.4.2))(typescript@5.9.3) debug: 4.4.3 - eslint: 9.39.3(jiti@2.4.2) + eslint: 9.39.4(jiti@2.4.2) ts-api-utils: 2.4.0(typescript@5.9.3) typescript: 5.9.3 transitivePeerDependencies: - supports-color - '@typescript-eslint/type-utils@8.56.1(eslint@9.39.3(jiti@2.4.2))(typescript@5.9.3)': + '@typescript-eslint/type-utils@8.56.1(eslint@9.39.4(jiti@2.4.2))(typescript@5.9.3)': dependencies: '@typescript-eslint/types': 8.56.1 '@typescript-eslint/typescript-estree': 8.56.1(typescript@5.9.3) - '@typescript-eslint/utils': 8.56.1(eslint@9.39.3(jiti@2.4.2))(typescript@5.9.3) + '@typescript-eslint/utils': 8.56.1(eslint@9.39.4(jiti@2.4.2))(typescript@5.9.3) debug: 4.4.3 - eslint: 9.39.3(jiti@2.4.2) + eslint: 9.39.4(jiti@2.4.2) ts-api-utils: 2.4.0(typescript@5.9.3) typescript: 5.9.3 transitivePeerDependencies: @@ -9421,24 +9421,24 @@ snapshots: transitivePeerDependencies: - supports-color - '@typescript-eslint/utils@8.56.0(eslint@9.39.3(jiti@2.4.2))(typescript@5.9.3)': + '@typescript-eslint/utils@8.56.0(eslint@9.39.4(jiti@2.4.2))(typescript@5.9.3)': dependencies: - '@eslint-community/eslint-utils': 4.9.1(eslint@9.39.3(jiti@2.4.2)) + '@eslint-community/eslint-utils': 4.9.1(eslint@9.39.4(jiti@2.4.2)) '@typescript-eslint/scope-manager': 8.56.0 '@typescript-eslint/types': 8.56.0 '@typescript-eslint/typescript-estree': 8.56.0(typescript@5.9.3) - eslint: 9.39.3(jiti@2.4.2) + eslint: 9.39.4(jiti@2.4.2) typescript: 5.9.3 transitivePeerDependencies: - supports-color - '@typescript-eslint/utils@8.56.1(eslint@9.39.3(jiti@2.4.2))(typescript@5.9.3)': + '@typescript-eslint/utils@8.56.1(eslint@9.39.4(jiti@2.4.2))(typescript@5.9.3)': dependencies: - '@eslint-community/eslint-utils': 4.9.1(eslint@9.39.3(jiti@2.4.2)) + '@eslint-community/eslint-utils': 4.9.1(eslint@9.39.4(jiti@2.4.2)) '@typescript-eslint/scope-manager': 8.56.1 '@typescript-eslint/types': 8.56.1 '@typescript-eslint/typescript-estree': 8.56.1(typescript@5.9.3) - eslint: 9.39.3(jiti@2.4.2) + eslint: 9.39.4(jiti@2.4.2) typescript: 5.9.3 transitivePeerDependencies: - supports-color @@ -9612,14 +9612,14 @@ snapshots: '@vue/devtools-shared@8.0.7': {} - '@vue/eslint-config-typescript@14.7.0(eslint-plugin-vue@10.8.0(@typescript-eslint/parser@8.56.1(eslint@9.39.3(jiti@2.4.2))(typescript@5.9.3))(eslint@9.39.3(jiti@2.4.2))(vue-eslint-parser@10.4.0(eslint@9.39.3(jiti@2.4.2))))(eslint@9.39.3(jiti@2.4.2))(typescript@5.9.3)': + '@vue/eslint-config-typescript@14.7.0(eslint-plugin-vue@10.8.0(@typescript-eslint/parser@8.56.1(eslint@9.39.4(jiti@2.4.2))(typescript@5.9.3))(eslint@9.39.4(jiti@2.4.2))(vue-eslint-parser@10.4.0(eslint@9.39.4(jiti@2.4.2))))(eslint@9.39.4(jiti@2.4.2))(typescript@5.9.3)': dependencies: - '@typescript-eslint/utils': 8.56.0(eslint@9.39.3(jiti@2.4.2))(typescript@5.9.3) - eslint: 9.39.3(jiti@2.4.2) - eslint-plugin-vue: 10.8.0(@typescript-eslint/parser@8.56.1(eslint@9.39.3(jiti@2.4.2))(typescript@5.9.3))(eslint@9.39.3(jiti@2.4.2))(vue-eslint-parser@10.4.0(eslint@9.39.3(jiti@2.4.2))) + '@typescript-eslint/utils': 8.56.0(eslint@9.39.4(jiti@2.4.2))(typescript@5.9.3) + eslint: 9.39.4(jiti@2.4.2) + eslint-plugin-vue: 10.8.0(@typescript-eslint/parser@8.56.1(eslint@9.39.4(jiti@2.4.2))(typescript@5.9.3))(eslint@9.39.4(jiti@2.4.2))(vue-eslint-parser@10.4.0(eslint@9.39.4(jiti@2.4.2))) fast-glob: 3.3.3 - typescript-eslint: 8.56.0(eslint@9.39.3(jiti@2.4.2))(typescript@5.9.3) - vue-eslint-parser: 10.4.0(eslint@9.39.3(jiti@2.4.2)) + typescript-eslint: 8.56.0(eslint@9.39.4(jiti@2.4.2))(typescript@5.9.3) + vue-eslint-parser: 10.4.0(eslint@9.39.4(jiti@2.4.2)) optionalDependencies: typescript: 5.9.3 transitivePeerDependencies: @@ -10534,25 +10534,25 @@ snapshots: optionalDependencies: source-map: 0.6.1 - eslint-plugin-depend@1.5.0(eslint@9.39.3(jiti@2.4.2)): + eslint-plugin-depend@1.5.0(eslint@9.39.4(jiti@2.4.2)): dependencies: empathic: 2.0.0 - eslint: 9.39.3(jiti@2.4.2) + eslint: 9.39.4(jiti@2.4.2) module-replacements: 2.11.0 semver: 7.7.3 - eslint-plugin-vue@10.8.0(@typescript-eslint/parser@8.56.1(eslint@9.39.3(jiti@2.4.2))(typescript@5.9.3))(eslint@9.39.3(jiti@2.4.2))(vue-eslint-parser@10.4.0(eslint@9.39.3(jiti@2.4.2))): + eslint-plugin-vue@10.8.0(@typescript-eslint/parser@8.56.1(eslint@9.39.4(jiti@2.4.2))(typescript@5.9.3))(eslint@9.39.4(jiti@2.4.2))(vue-eslint-parser@10.4.0(eslint@9.39.4(jiti@2.4.2))): dependencies: - '@eslint-community/eslint-utils': 4.9.1(eslint@9.39.3(jiti@2.4.2)) - eslint: 9.39.3(jiti@2.4.2) + '@eslint-community/eslint-utils': 4.9.1(eslint@9.39.4(jiti@2.4.2)) + eslint: 9.39.4(jiti@2.4.2) natural-compare: 1.4.0 nth-check: 2.1.1 postcss-selector-parser: 7.1.1 semver: 7.7.3 - vue-eslint-parser: 10.4.0(eslint@9.39.3(jiti@2.4.2)) + vue-eslint-parser: 10.4.0(eslint@9.39.4(jiti@2.4.2)) xml-name-validator: 4.0.0 optionalDependencies: - '@typescript-eslint/parser': 8.56.1(eslint@9.39.3(jiti@2.4.2))(typescript@5.9.3) + '@typescript-eslint/parser': 8.56.1(eslint@9.39.4(jiti@2.4.2))(typescript@5.9.3) eslint-scope@8.4.0: dependencies: @@ -10565,15 +10565,15 @@ snapshots: eslint-visitor-keys@5.0.0: {} - eslint@9.39.3(jiti@2.4.2): + eslint@9.39.4(jiti@2.4.2): dependencies: - '@eslint-community/eslint-utils': 4.9.1(eslint@9.39.3(jiti@2.4.2)) + '@eslint-community/eslint-utils': 4.9.1(eslint@9.39.4(jiti@2.4.2)) '@eslint-community/regexpp': 4.12.2 - '@eslint/config-array': 0.21.1 + '@eslint/config-array': 0.21.2 '@eslint/config-helpers': 0.4.2 '@eslint/core': 0.17.0 - '@eslint/eslintrc': 3.3.1 - '@eslint/js': 9.39.3 + '@eslint/eslintrc': 3.3.5 + '@eslint/js': 9.39.4 '@eslint/plugin-kit': 0.4.1 '@humanfs/node': 0.16.6 '@humanwhocodes/module-importer': 1.0.1 @@ -13261,13 +13261,13 @@ snapshots: typed-query-selector@2.12.0: {} - typescript-eslint@8.56.0(eslint@9.39.3(jiti@2.4.2))(typescript@5.9.3): + typescript-eslint@8.56.0(eslint@9.39.4(jiti@2.4.2))(typescript@5.9.3): dependencies: - '@typescript-eslint/eslint-plugin': 8.56.0(@typescript-eslint/parser@8.56.0(eslint@9.39.3(jiti@2.4.2))(typescript@5.9.3))(eslint@9.39.3(jiti@2.4.2))(typescript@5.9.3) - '@typescript-eslint/parser': 8.56.0(eslint@9.39.3(jiti@2.4.2))(typescript@5.9.3) + '@typescript-eslint/eslint-plugin': 8.56.0(@typescript-eslint/parser@8.56.0(eslint@9.39.4(jiti@2.4.2))(typescript@5.9.3))(eslint@9.39.4(jiti@2.4.2))(typescript@5.9.3) + '@typescript-eslint/parser': 8.56.0(eslint@9.39.4(jiti@2.4.2))(typescript@5.9.3) '@typescript-eslint/typescript-estree': 8.56.0(typescript@5.9.3) - '@typescript-eslint/utils': 8.56.0(eslint@9.39.3(jiti@2.4.2))(typescript@5.9.3) - eslint: 9.39.3(jiti@2.4.2) + '@typescript-eslint/utils': 8.56.0(eslint@9.39.4(jiti@2.4.2))(typescript@5.9.3) + eslint: 9.39.4(jiti@2.4.2) typescript: 5.9.3 transitivePeerDependencies: - supports-color @@ -13582,10 +13582,10 @@ snapshots: dependencies: vue: 3.5.27(typescript@5.9.3) - vue-eslint-parser@10.4.0(eslint@9.39.3(jiti@2.4.2)): + vue-eslint-parser@10.4.0(eslint@9.39.4(jiti@2.4.2)): dependencies: debug: 4.4.3 - eslint: 9.39.3(jiti@2.4.2) + eslint: 9.39.4(jiti@2.4.2) eslint-scope: 8.4.0 eslint-visitor-keys: 5.0.0 espree: 10.4.0 From d4b03026f0b98734a95e9cc22d3e77e89a7d3f4f Mon Sep 17 00:00:00 2001 From: kolaente Date: Sun, 8 Mar 2026 15:52:53 +0100 Subject: [PATCH 032/142] feat: add conversational email template and rendering Add conversational email style with GitHub-inspired header design. Includes mail struct extensions (headerLine, conversational flag), CreateConversationalHeader helper, HTML template with avatar support, p-tag wrapping for content lines, plain-text stripping, and conditional action link rendering. --- pkg/notifications/mail.go | 60 +++++++-- pkg/notifications/mail_render.go | 206 +++++++++++++++++++++++++++++-- 2 files changed, 247 insertions(+), 19 deletions(-) diff --git a/pkg/notifications/mail.go b/pkg/notifications/mail.go index 481553f62..8c4ede991 100644 --- a/pkg/notifications/mail.go +++ b/pkg/notifications/mail.go @@ -26,16 +26,18 @@ import ( // Mail is a mail message type Mail struct { - from string - to string - subject string - actionText string - actionURL string - greeting string - introLines []*mailLine - outroLines []*mailLine - footerLines []*mailLine - threadID string + from string + to string + subject string + actionText string + actionURL string + greeting string + headerLine *mailLine + introLines []*mailLine + outroLines []*mailLine + footerLines []*mailLine + threadID string + conversational bool } type mailLine struct { @@ -101,12 +103,50 @@ func (m *Mail) HTML(line string) *Mail { return m.appendLine(line, true) } +// HeaderLine sets the header line for conversational emails (e.g., "@user mentioned you") +func (m *Mail) HeaderLine(line string) *Mail { + m.headerLine = &mailLine{Text: line, isHTML: true} + return m +} + // ThreadID sets the thread ID of the mail message for email threading func (m *Mail) ThreadID(threadID string) *Mail { m.threadID = threadID return m } +// Conversational sets the email to use conversational styling +func (m *Mail) Conversational() *Mail { + m.conversational = true + return m +} + +// IsConversational returns whether the email uses conversational styling +func (m *Mail) IsConversational() bool { + return m.conversational +} + +// CreateConversationalHeader creates a GitHub-style header line with avatar, action text, and task reference. +// The action string should already contain the doer's name (e.g. "alice left a comment"). +func CreateConversationalHeader(avatarDataURI, action, taskURL, projectTitle, taskIdentifier, taskTitle string) string { + avatarHTML := "" + if avatarDataURI != "" { + avatarHTML = fmt.Sprintf( + ``, + avatarDataURI, + ) + } + return fmt.Sprintf( + `%s%s (%s > %s) %s`, + avatarHTML, + action, + taskURL, + projectTitle, + taskTitle, + taskIdentifier, + ) +} + func (m *Mail) appendLine(line string, isHTML bool) *Mail { if m.actionURL == "" { m.introLines = append(m.introLines, &mailLine{ diff --git a/pkg/notifications/mail_render.go b/pkg/notifications/mail_render.go index 7539aded5..67b254d35 100644 --- a/pkg/notifications/mail_render.go +++ b/pkg/notifications/mail_render.go @@ -20,6 +20,8 @@ import ( "bytes" "embed" templatehtml "html/template" + "regexp" + "strings" templatetext "text/template" "code.vikunja.io/api/pkg/config" @@ -45,11 +47,25 @@ const mailTemplatePlain = ` {{ $line.Text }} {{ end }}` +const mailTemplateConversationalPlain = ` +{{ if .HeaderLinePlain }}{{ .HeaderLinePlain }} +{{ end }}{{ range $line := .IntroLines}} +{{ $line.Text }} +{{ end }} +{{ if .ActionURL }}{{ .ActionText }}: +{{ .ActionURL }}{{end}} +{{ range $line := .OutroLines}} +{{ $line.Text }} +{{ end }} +{{ range $line := .FooterLines}} +{{ $line.Text }} +{{ end }}` + const mailTemplateHTML = ` - + diff --git a/frontend/src/i18n/lang/en.json b/frontend/src/i18n/lang/en.json index 90b19a1ab..b7f4890a9 100644 --- a/frontend/src/i18n/lang/en.json +++ b/frontend/src/i18n/lang/en.json @@ -186,6 +186,10 @@ "backgroundBrightness": { "title": "Background brightness" }, + "webhooks": { + "title": "Webhook Notifications", + "description": "Configure webhook URLs to receive POST requests when reminder or overdue events fire. These webhooks receive events from all your projects." + }, "apiTokens": { "title": "API Tokens", "general": "API tokens allow you to use Vikunja's API without user credentials.", diff --git a/frontend/src/modelTypes/IUserSettings.ts b/frontend/src/modelTypes/IUserSettings.ts index 8edbd438f..246321d74 100644 --- a/frontend/src/modelTypes/IUserSettings.ts +++ b/frontend/src/modelTypes/IUserSettings.ts @@ -1,4 +1,3 @@ - import type {IAbstract} from './IAbstract' import type {IProject} from './IProject' import type {PrefixMode} from '@/modules/parseTaskText' diff --git a/frontend/src/modelTypes/IWebhook.ts b/frontend/src/modelTypes/IWebhook.ts index 268d7260b..137a386c5 100644 --- a/frontend/src/modelTypes/IWebhook.ts +++ b/frontend/src/modelTypes/IWebhook.ts @@ -4,9 +4,10 @@ import type {IUser} from '@/modelTypes/IUser' export interface IWebhook extends IAbstract { id: number projectId: number - secret: string + userId: number + secret: string basicauthuser: string - basicauthpassword: string + basicauthpassword: string targetUrl: string events: string[] createdBy: IUser diff --git a/frontend/src/models/userSettings.ts b/frontend/src/models/userSettings.ts index 7b61a50ed..a4fcc91fb 100644 --- a/frontend/src/models/userSettings.ts +++ b/frontend/src/models/userSettings.ts @@ -25,11 +25,13 @@ export default class UserSettingsModel extends AbstractModel impl quickAddMagicMode: PrefixMode.Default, colorSchema: 'auto', allowIconChanges: true, + filterIdUsedOnOverview: null, defaultView: DEFAULT_PROJECT_VIEW_SETTINGS.FIRST, minimumPriority: PRIORITIES.MEDIUM, dateDisplay: DATE_DISPLAY.RELATIVE, timeFormat: TIME_FORMAT.HOURS_24, defaultTaskRelationType: RELATION_KIND.RELATED, + backgroundBrightness: null, alwaysShowBucketTaskCount: false, sidebarWidth: null, commentSortOrder: 'asc', diff --git a/frontend/src/models/webhook.ts b/frontend/src/models/webhook.ts index a92d4a6f5..e86c7bdec 100644 --- a/frontend/src/models/webhook.ts +++ b/frontend/src/models/webhook.ts @@ -5,6 +5,7 @@ import UserModel from '@/models/user' export default class WebhookModel extends AbstractModel implements IWebhook { id = 0 projectId = 0 + userId = 0 secret = '' basicauthuser = '' basicauthpassword = '' diff --git a/frontend/src/router/index.ts b/frontend/src/router/index.ts index ceacc0b74..c19b4642d 100644 --- a/frontend/src/router/index.ts +++ b/frontend/src/router/index.ts @@ -144,6 +144,11 @@ const router = createRouter({ name: 'user.settings.sessions', component: () => import('@/views/user/settings/Sessions.vue'), }, + { + path: '/user/settings/webhooks', + name: 'user.settings.webhooks', + component: () => import('@/views/user/settings/Webhooks.vue'), + }, { path: '/user/settings/migrate', name: 'migrate.start', diff --git a/frontend/src/services/webhook.ts b/frontend/src/services/webhook.ts index f2830c889..2c906bcc8 100644 --- a/frontend/src/services/webhook.ts +++ b/frontend/src/services/webhook.ts @@ -27,3 +27,29 @@ export default class WebhookService extends AbstractService { } } } + +export class UserWebhookService extends AbstractService { + constructor() { + super({ + getAll: '/user/settings/webhooks', + create: '/user/settings/webhooks', + update: '/user/settings/webhooks/{id}', + delete: '/user/settings/webhooks/{id}', + }) + } + + modelFactory(data) { + return new WebhookModel(data) + } + + async getAvailableEvents(): Promise { + const cancel = this.setLoading() + + try { + const response = await this.http.get('/user/settings/webhooks/events') + return response.data + } finally { + cancel() + } + } +} diff --git a/frontend/src/stores/config.ts b/frontend/src/stores/config.ts index f759b07df..e5f70d54f 100644 --- a/frontend/src/stores/config.ts +++ b/frontend/src/stores/config.ts @@ -28,6 +28,7 @@ export interface ConfigState { userDeletionEnabled: boolean, taskCommentsEnabled: boolean, demoModeEnabled: boolean, + webhooksEnabled: boolean, auth: { local: { enabled: boolean, @@ -66,6 +67,7 @@ export const useConfigStore = defineStore('config', () => { userDeletionEnabled: true, taskCommentsEnabled: true, demoModeEnabled: false, + webhooksEnabled: false, auth: { local: { enabled: true, diff --git a/frontend/src/views/project/settings/ProjectSettingsWebhooks.vue b/frontend/src/views/project/settings/ProjectSettingsWebhooks.vue index f745b97a8..6159cd513 100644 --- a/frontend/src/views/project/settings/ProjectSettingsWebhooks.vue +++ b/frontend/src/views/project/settings/ProjectSettingsWebhooks.vue @@ -7,21 +7,14 @@ import {useTitle} from '@vueuse/core' import ProjectService from '@/services/project' import ProjectModel from '@/models/project' import type {IProject} from '@/modelTypes/IProject' +import type {IWebhook} from '@/modelTypes/IWebhook' import CreateEdit from '@/components/misc/CreateEdit.vue' +import WebhookManager from '@/components/misc/WebhookManager.vue' import {useBaseStore} from '@/stores/base' -import type {IWebhook} from '@/modelTypes/IWebhook' import WebhookService from '@/services/webhook' -import {formatDateShort} from '@/helpers/time/formatDate' -import User from '@/components/misc/User.vue' -import WebhookModel from '@/models/webhook' -import BaseButton from '@/components/base/BaseButton.vue' -import FancyCheckbox from '@/components/input/FancyCheckbox.vue' -import FormField from '@/components/input/FormField.vue' -import Expandable from '@/components/base/Expandable.vue' import {success} from '@/message' -import {isValidHttpUrl} from '@/helpers/isValidHttpUrl' defineOptions({name: 'ProjectSettingWebhooks'}) @@ -30,9 +23,6 @@ const {t} = useI18n({useScope: 'global'}) const project = ref() useTitle(t('project.webhooks.title')) -const showNewForm = ref(false) -const showBasicAuth = ref(false) - async function loadProject(projectId: number) { const projectService = new ProjectService() const newProject = await projectService.get(new ProjectModel({id: projectId})) @@ -49,75 +39,35 @@ const projectId = computed(() => route.params.projectId !== undefined watchEffect(() => projectId.value !== undefined && loadProject(projectId.value)) -const webhooks = ref() +const webhooks = ref([]) const webhookService = new WebhookService() -const availableEvents = ref() +const availableEvents = ref([]) +const loading = ref(false) async function loadWebhooks() { - webhooks.value = await webhookService.getAll({projectId: project.value.id}) - availableEvents.value = await webhookService.getAvailableEvents() - // Initialize all events to false to avoid undefined modelValue errors - newWebhookEvents.value = Object.fromEntries( - availableEvents.value.map(event => [event, false]), - ) + loading.value = true + try { + webhooks.value = await webhookService.getAll({projectId: project.value.id}) + availableEvents.value = await webhookService.getAvailableEvents() + } finally { + loading.value = false + } } -const showDeleteModal = ref(false) -const webhookIdToDelete = ref() +async function handleCreate(webhook: IWebhook) { + webhook.projectId = project.value.id + const created = await webhookService.create(webhook) + webhooks.value.push(created) +} -async function deleteWebhook() { +async function handleDelete(webhookId: number) { await webhookService.delete({ - id: webhookIdToDelete.value, + id: webhookId, projectId: project.value.id, }) - showDeleteModal.value = false success({message: t('project.webhooks.deleteSuccess')}) await loadWebhooks() } - -const newWebhook = ref(new WebhookModel()) -const newWebhookEvents = ref({}) - -async function create() { - - validateTargetUrl() - if (!webhookTargetUrlValid.value) { - return - } - - const selectedEvents = getSelectedEventsArray() - newWebhook.value.events = selectedEvents - - validateSelectedEvents() - if (!selectedEventsValid.value) { - return - } - - newWebhook.value.projectId = project.value.id - const created = await webhookService.create(newWebhook.value) - webhooks.value.push(created) - newWebhook.value = new WebhookModel() - showNewForm.value = false -} - -const webhookTargetUrlValid = ref(true) - -function validateTargetUrl() { - webhookTargetUrlValid.value = isValidHttpUrl(newWebhook.value.targetUrl) -} - -const selectedEventsValid = ref(true) - -function getSelectedEventsArray() { - return Object.entries(newWebhookEvents.value) - .filter(([, use]) => use) - .map(([event]) => event) -} - -function validateSelectedEvents() { - const events = getSelectedEventsArray() - selectedEventsValid.value = events.length > 0 -} - - diff --git a/frontend/src/views/user/Settings.vue b/frontend/src/views/user/Settings.vue index 81e21409d..155316f37 100644 --- a/frontend/src/views/user/Settings.vue +++ b/frontend/src/views/user/Settings.vue @@ -64,6 +64,7 @@ const caldavEnabled = computed(() => configStore.caldavEnabled) const migratorsEnabled = computed(() => configStore.migratorsEnabled) const isLocalUser = computed(() => authStore.info?.isLocalUser) const userDeletionEnabled = computed(() => configStore.userDeletionEnabled) +const webhooksEnabled = computed(() => configStore.webhooksEnabled) const navigationItems = computed(() => { const items = [ @@ -112,6 +113,11 @@ const navigationItems = computed(() => { title: t('user.settings.sessions.title'), routeName: 'user.settings.sessions', }, + { + title: t('user.settings.webhooks.title'), + routeName: 'user.settings.webhooks', + condition: webhooksEnabled.value, + }, { title: t('user.deletion.title'), routeName: 'user.settings.deletion', diff --git a/frontend/src/views/user/settings/Webhooks.vue b/frontend/src/views/user/settings/Webhooks.vue new file mode 100644 index 000000000..2a087caa4 --- /dev/null +++ b/frontend/src/views/user/settings/Webhooks.vue @@ -0,0 +1,66 @@ + + + From 05cc65fe9e4fa448cda437d58480a9f3f19d69ed Mon Sep 17 00:00:00 2001 From: kolaente Date: Sun, 8 Mar 2026 19:25:59 +0100 Subject: [PATCH 040/142] test: add e2e tests for user-level webhooks Add comprehensive e2e tests for user-level webhook CRUD operations and update existing project webhook tests to use LoadFixtures() for cleanup instead of manual DELETE queries. --- pkg/e2etests/user_webhook_test.go | 430 ++++++++++++++++++++++++++++++ pkg/e2etests/webhook_test.go | 5 +- 2 files changed, 432 insertions(+), 3 deletions(-) create mode 100644 pkg/e2etests/user_webhook_test.go diff --git a/pkg/e2etests/user_webhook_test.go b/pkg/e2etests/user_webhook_test.go new file mode 100644 index 000000000..6cad410f0 --- /dev/null +++ b/pkg/e2etests/user_webhook_test.go @@ -0,0 +1,430 @@ +// Vikunja is a to-do list application to facilitate your life. +// Copyright 2018-present Vikunja and contributors. All rights reserved. +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU Affero General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU Affero General Public License for more details. +// +// You should have received a copy of the GNU Affero General Public License +// along with this program. If not, see . + +package e2etests + +import ( + "context" + "crypto/hmac" + "crypto/sha256" + "encoding/hex" + "encoding/json" + "io" + "net/http" + "net/http/httptest" + "sync" + "testing" + "time" + + "code.vikunja.io/api/pkg/db" + "code.vikunja.io/api/pkg/events" + "code.vikunja.io/api/pkg/models" + "code.vikunja.io/api/pkg/user" + + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" +) + +// webhookCapture is a test helper that starts an HTTP server to capture webhook payloads. +type webhookCapture struct { + server *httptest.Server + payloads chan webhookDelivery + mu sync.Mutex + received []webhookDelivery +} + +type webhookDelivery struct { + Body []byte + Headers http.Header +} + +func newWebhookCapture() *webhookCapture { + wc := &webhookCapture{ + payloads: make(chan webhookDelivery, 10), + } + wc.server = httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + body, _ := io.ReadAll(r.Body) + delivery := webhookDelivery{ + Body: body, + Headers: r.Header.Clone(), + } + wc.mu.Lock() + wc.received = append(wc.received, delivery) + wc.mu.Unlock() + select { + case wc.payloads <- delivery: + default: + } + w.WriteHeader(http.StatusOK) + })) + return wc +} + +func (wc *webhookCapture) URL() string { + return wc.server.URL +} + +func (wc *webhookCapture) Close() { + wc.server.Close() +} + +// waitForPayload waits for a webhook payload to arrive within 10 seconds. +func (wc *webhookCapture) waitForPayload(t *testing.T) webhookDelivery { + t.Helper() + select { + case d := <-wc.payloads: + return d + case <-time.After(10 * time.Second): + t.Fatal("Webhook payload not received within timeout") + return webhookDelivery{} // unreachable + } +} + +// assertNoPayload asserts that no webhook payload arrives within the given duration. +func (wc *webhookCapture) assertNoPayload(t *testing.T, wait time.Duration) { + t.Helper() + select { + case d := <-wc.payloads: + t.Fatalf("Expected no webhook payload but received one: %s", string(d.Body)) + case <-time.After(wait): + // success — nothing arrived + } +} + +// insertUserWebhook creates a user-level webhook (no project_id) in the database. +func insertUserWebhook(t *testing.T, userID int64, targetURL string, evts []string) { + t.Helper() + s := db.NewSession() + defer s.Close() + _, err := s.Insert(&models.Webhook{ + TargetURL: targetURL, + Events: evts, + UserID: userID, + CreatedByID: userID, + }) + require.NoError(t, err) + require.NoError(t, s.Commit()) +} + +// insertUserWebhookWithSecret creates a user-level webhook with an HMAC secret. +func insertUserWebhookWithSecret(t *testing.T, userID int64, targetURL string, evts []string, secret string) { + t.Helper() + s := db.NewSession() + defer s.Close() + _, err := s.Insert(&models.Webhook{ + TargetURL: targetURL, + Events: evts, + UserID: userID, + CreatedByID: userID, + Secret: secret, + }) + require.NoError(t, err) + require.NoError(t, s.Commit()) +} + +// resetWebhooks reloads all fixtures to start each test from a clean database state. +func resetWebhooks(t *testing.T) { + t.Helper() + require.NoError(t, db.LoadFixtures()) +} + +// parseWebhookPayload parses a webhook delivery body into a structured map. +func parseWebhookPayload(t *testing.T, d webhookDelivery) map[string]interface{} { + t.Helper() + var payload map[string]interface{} + require.NoError(t, json.Unmarshal(d.Body, &payload)) + return payload +} + +func TestUserWebhookTaskOverdueE2E(t *testing.T) { + ctx, cancel := context.WithCancel(context.Background()) + defer cancel() + + _, err := setupE2ETestEnv(ctx) + require.NoError(t, err) + + capture := newWebhookCapture() + defer capture.Close() + + resetWebhooks(t) + insertUserWebhook(t, testuser1.ID, capture.URL(), []string{"task.overdue"}) + + // Dispatch a TaskOverdueEvent directly — this simulates the overdue cron job + err = events.Dispatch(&models.TaskOverdueEvent{ + Task: &models.Task{ + ID: 1, + Title: "Overdue task", + ProjectID: 1, + }, + User: &testuser1, + Project: &models.Project{ID: 1, Title: "Test Project"}, + }) + require.NoError(t, err) + + delivery := capture.waitForPayload(t) + payload := parseWebhookPayload(t, delivery) + + assert.Equal(t, "task.overdue", payload["event_name"]) + data, ok := payload["data"].(map[string]interface{}) + require.True(t, ok, "payload.data should be a map") + task, ok := data["task"].(map[string]interface{}) + require.True(t, ok, "payload.data.task should be a map") + assert.Equal(t, "Overdue task", task["title"]) +} + +func TestUserWebhookTaskReminderFiredE2E(t *testing.T) { + ctx, cancel := context.WithCancel(context.Background()) + defer cancel() + + _, err := setupE2ETestEnv(ctx) + require.NoError(t, err) + + capture := newWebhookCapture() + defer capture.Close() + + resetWebhooks(t) + insertUserWebhook(t, testuser1.ID, capture.URL(), []string{"task.reminder.fired"}) + + // Dispatch a TaskReminderFiredEvent directly — simulates the reminder cron job + err = events.Dispatch(&models.TaskReminderFiredEvent{ + Task: &models.Task{ + ID: 1, + Title: "Reminder task", + ProjectID: 1, + }, + User: &testuser1, + Project: &models.Project{ID: 1, Title: "Test Project"}, + }) + require.NoError(t, err) + + delivery := capture.waitForPayload(t) + payload := parseWebhookPayload(t, delivery) + + assert.Equal(t, "task.reminder.fired", payload["event_name"]) + data, ok := payload["data"].(map[string]interface{}) + require.True(t, ok, "payload.data should be a map") + task, ok := data["task"].(map[string]interface{}) + require.True(t, ok, "payload.data.task should be a map") + assert.Equal(t, "Reminder task", task["title"]) +} + +func TestUserWebhookDoesNotFireForOtherUsers(t *testing.T) { + ctx, cancel := context.WithCancel(context.Background()) + defer cancel() + + _, err := setupE2ETestEnv(ctx) + require.NoError(t, err) + + capture := newWebhookCapture() + defer capture.Close() + + resetWebhooks(t) + // Create a user-level webhook for user 2 + insertUserWebhook(t, 2, capture.URL(), []string{"task.overdue"}) + + // Dispatch an overdue event for user 1 — user 2's webhook should NOT fire + err = events.Dispatch(&models.TaskOverdueEvent{ + Task: &models.Task{ + ID: 1, + Title: "Overdue for user 1", + ProjectID: 1, + }, + User: &testuser1, + Project: &models.Project{ID: 1, Title: "Test Project"}, + }) + require.NoError(t, err) + + capture.assertNoPayload(t, 3*time.Second) +} + +func TestUserWebhookAndProjectWebhookBothFire(t *testing.T) { + ctx, cancel := context.WithCancel(context.Background()) + defer cancel() + + _, err := setupE2ETestEnv(ctx) + require.NoError(t, err) + + userCapture := newWebhookCapture() + defer userCapture.Close() + projectCapture := newWebhookCapture() + defer projectCapture.Close() + + resetWebhooks(t) + + // User-level webhook for user 1 listening to task.overdue + insertUserWebhook(t, testuser1.ID, userCapture.URL(), []string{"task.overdue"}) + + // Project-level webhook for project 1 listening to task.overdue + s := db.NewSession() + _, err = s.Insert(&models.Webhook{ + TargetURL: projectCapture.URL(), + Events: []string{"task.overdue"}, + ProjectID: 1, + CreatedByID: 1, + }) + require.NoError(t, err) + require.NoError(t, s.Commit()) + s.Close() + + // Dispatch overdue event — both project-level and user-level webhooks should fire + err = events.Dispatch(&models.TaskOverdueEvent{ + Task: &models.Task{ + ID: 1, + Title: "Both webhooks overdue", + ProjectID: 1, + }, + User: &testuser1, + Project: &models.Project{ID: 1, Title: "Test Project"}, + }) + require.NoError(t, err) + + // Both should receive the payload + projectDelivery := projectCapture.waitForPayload(t) + projectPayload := parseWebhookPayload(t, projectDelivery) + assert.Equal(t, "task.overdue", projectPayload["event_name"]) + + userDelivery := userCapture.waitForPayload(t) + userPayload := parseWebhookPayload(t, userDelivery) + assert.Equal(t, "task.overdue", userPayload["event_name"]) +} + +func TestUserWebhookHMACSigning(t *testing.T) { + ctx, cancel := context.WithCancel(context.Background()) + defer cancel() + + _, err := setupE2ETestEnv(ctx) + require.NoError(t, err) + + capture := newWebhookCapture() + defer capture.Close() + + resetWebhooks(t) + secret := "test-hmac-secret-for-user-webhook" + insertUserWebhookWithSecret(t, testuser1.ID, capture.URL(), []string{"task.overdue"}, secret) + + err = events.Dispatch(&models.TaskOverdueEvent{ + Task: &models.Task{ + ID: 1, + Title: "HMAC overdue", + ProjectID: 1, + }, + User: &testuser1, + Project: &models.Project{ID: 1, Title: "Test Project"}, + }) + require.NoError(t, err) + + delivery := capture.waitForPayload(t) + + // Verify the HMAC signature header is present and correct + signature := delivery.Headers.Get("X-Vikunja-Signature") + require.NotEmpty(t, signature, "X-Vikunja-Signature header should be set") + + mac := hmac.New(sha256.New, []byte(secret)) + _, err = mac.Write(delivery.Body) + require.NoError(t, err) + expectedSig := hex.EncodeToString(mac.Sum(nil)) + assert.Equal(t, expectedSig, signature, "HMAC signature should match") +} + +func TestUserWebhookOnlyMatchesSubscribedEvents(t *testing.T) { + ctx, cancel := context.WithCancel(context.Background()) + defer cancel() + + _, err := setupE2ETestEnv(ctx) + require.NoError(t, err) + + capture := newWebhookCapture() + defer capture.Close() + + resetWebhooks(t) + // Subscribe only to task.reminder.fired — task.overdue should NOT trigger it + insertUserWebhook(t, testuser1.ID, capture.URL(), []string{"task.reminder.fired"}) + + err = events.Dispatch(&models.TaskOverdueEvent{ + Task: &models.Task{ + ID: 1, + Title: "Wrong event", + ProjectID: 1, + }, + User: &testuser1, + Project: &models.Project{ID: 1, Title: "Test Project"}, + }) + require.NoError(t, err) + + capture.assertNoPayload(t, 3*time.Second) +} + +func TestUserWebhookDoesNotFireForProjectEvents(t *testing.T) { + ctx, cancel := context.WithCancel(context.Background()) + defer cancel() + + e, err := setupE2ETestEnv(ctx) + require.NoError(t, err) + + capture := newWebhookCapture() + defer capture.Close() + + resetWebhooks(t) + // User-level webhook subscribed to task.updated (a non-user-directed event) + insertUserWebhook(t, testuser1.ID, capture.URL(), []string{"task.updated"}) + + // Update task via the web handler — user-level webhooks should NOT fire + // for project-scoped events like task.updated + _, err = testUpdateWithUser(e, t, &testuser1, + map[string]string{"projecttask": "1"}, + `{"title":"Should not trigger user webhook"}`, + ) + require.NoError(t, err) + + capture.assertNoPayload(t, 3*time.Second) +} + +func TestUserWebhookTasksOverdueBatchE2E(t *testing.T) { + ctx, cancel := context.WithCancel(context.Background()) + defer cancel() + + _, err := setupE2ETestEnv(ctx) + require.NoError(t, err) + + capture := newWebhookCapture() + defer capture.Close() + + resetWebhooks(t) + insertUserWebhook(t, testuser1.ID, capture.URL(), []string{"tasks.overdue"}) + + // Dispatch a batch TasksOverdueEvent + err = events.Dispatch(&models.TasksOverdueEvent{ + Tasks: []*models.Task{ + {ID: 1, Title: "Overdue 1", ProjectID: 1}, + {ID: 2, Title: "Overdue 2", ProjectID: 1}, + }, + User: &user.User{ID: testuser1.ID, Username: testuser1.Username}, + Projects: map[int64]*models.Project{ + 1: {ID: 1, Title: "Test Project"}, + }, + }) + require.NoError(t, err) + + delivery := capture.waitForPayload(t) + payload := parseWebhookPayload(t, delivery) + + assert.Equal(t, "tasks.overdue", payload["event_name"]) + data, ok := payload["data"].(map[string]interface{}) + require.True(t, ok, "payload.data should be a map") + tasks, ok := data["tasks"].([]interface{}) + require.True(t, ok, "payload.data.tasks should be an array") + assert.Len(t, tasks, 2) +} diff --git a/pkg/e2etests/webhook_test.go b/pkg/e2etests/webhook_test.go index 0fe4755a7..c56b14eef 100644 --- a/pkg/e2etests/webhook_test.go +++ b/pkg/e2etests/webhook_test.go @@ -52,12 +52,11 @@ func TestTaskUpdateWebhookE2E(t *testing.T) { })) defer ts.Close() - // Clean up any leftover webhook rows from previous test runs, then insert + // Reload fixtures to start from a clean state, then insert // a fresh webhook for project 1 listening to "task.updated". + require.NoError(t, db.LoadFixtures()) s := db.NewSession() defer s.Close() - _, err = s.Where("1=1").Delete(&models.Webhook{}) - require.NoError(t, err) _, err = s.Insert(&models.Webhook{ TargetURL: ts.URL, Events: []string{"task.updated"}, From 74771ed132e0b30a5172f7cbbb4552abb891fcc9 Mon Sep 17 00:00:00 2001 From: "Frederick [Bot]" Date: Sun, 8 Mar 2026 18:53:26 +0000 Subject: [PATCH 041/142] [skip ci] Updated swagger docs --- pkg/swagger/docs.go | 217 +++++++++++++++++++++++++++++++++++++++ pkg/swagger/swagger.json | 217 +++++++++++++++++++++++++++++++++++++++ pkg/swagger/swagger.yaml | 140 +++++++++++++++++++++++++ 3 files changed, 574 insertions(+) diff --git a/pkg/swagger/docs.go b/pkg/swagger/docs.go index b730cea33..a5747be2b 100644 --- a/pkg/swagger/docs.go +++ b/pkg/swagger/docs.go @@ -7477,6 +7477,219 @@ const docTemplate = `{ } } }, + "/user/settings/webhooks": { + "get": { + "security": [ + { + "JWTKeyAuth": [] + } + ], + "description": "Get all webhook targets configured for the current user (not project-specific).", + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "webhooks" + ], + "summary": "Get all user-level webhook targets", + "responses": { + "200": { + "description": "The list of webhook targets", + "schema": { + "type": "array", + "items": { + "$ref": "#/definitions/models.Webhook" + } + } + }, + "500": { + "description": "Internal server error", + "schema": { + "$ref": "#/definitions/models.Message" + } + } + } + }, + "put": { + "security": [ + { + "JWTKeyAuth": [] + } + ], + "description": "Create a webhook target for the current user that receives events across all projects.", + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "webhooks" + ], + "summary": "Create a user-level webhook target", + "parameters": [ + { + "description": "The webhook target", + "name": "webhook", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/models.Webhook" + } + } + ], + "responses": { + "200": { + "description": "The created webhook target", + "schema": { + "$ref": "#/definitions/models.Webhook" + } + }, + "400": { + "description": "Invalid webhook", + "schema": { + "$ref": "#/definitions/web.HTTPError" + } + }, + "500": { + "description": "Internal server error", + "schema": { + "$ref": "#/definitions/models.Message" + } + } + } + } + }, + "/user/settings/webhooks/events": { + "get": { + "security": [ + { + "JWTKeyAuth": [] + } + ], + "description": "Get all webhook events that can be used with user-level webhook targets.", + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "webhooks" + ], + "summary": "Get available user-directed webhook events", + "responses": { + "200": { + "description": "The list of user-directed webhook events", + "schema": { + "type": "array", + "items": { + "type": "string" + } + } + } + } + } + }, + "/user/settings/webhooks/{id}": { + "post": { + "security": [ + { + "JWTKeyAuth": [] + } + ], + "description": "Update the events for a user-level webhook target.", + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "webhooks" + ], + "summary": "Update a user-level webhook target", + "parameters": [ + { + "type": "integer", + "description": "Webhook ID", + "name": "id", + "in": "path", + "required": true + } + ], + "responses": { + "200": { + "description": "The updated webhook target", + "schema": { + "$ref": "#/definitions/models.Webhook" + } + }, + "404": { + "description": "Webhook not found", + "schema": { + "$ref": "#/definitions/web.HTTPError" + } + }, + "500": { + "description": "Internal server error", + "schema": { + "$ref": "#/definitions/models.Message" + } + } + } + }, + "delete": { + "security": [ + { + "JWTKeyAuth": [] + } + ], + "description": "Delete a user-level webhook target.", + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "webhooks" + ], + "summary": "Delete a user-level webhook target", + "parameters": [ + { + "type": "integer", + "description": "Webhook ID", + "name": "id", + "in": "path", + "required": true + } + ], + "responses": { + "200": { + "description": "Successfully deleted", + "schema": { + "$ref": "#/definitions/models.Message" + } + }, + "404": { + "description": "Webhook not found", + "schema": { + "$ref": "#/definitions/web.HTTPError" + } + }, + "500": { + "description": "Internal server error", + "schema": { + "$ref": "#/definitions/models.Message" + } + } + } + } + }, "/user/timezones": { "get": { "security": [ @@ -9387,6 +9600,10 @@ const docTemplate = `{ "updated": { "description": "A timestamp when this webhook target was last updated. You cannot change this value.", "type": "string" + }, + "user_id": { + "description": "The user ID if this is a user-level webhook (mutually exclusive with ProjectID)", + "type": "integer" } } }, diff --git a/pkg/swagger/swagger.json b/pkg/swagger/swagger.json index 9fc6cabcc..96b2e114d 100644 --- a/pkg/swagger/swagger.json +++ b/pkg/swagger/swagger.json @@ -7469,6 +7469,219 @@ } } }, + "/user/settings/webhooks": { + "get": { + "security": [ + { + "JWTKeyAuth": [] + } + ], + "description": "Get all webhook targets configured for the current user (not project-specific).", + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "webhooks" + ], + "summary": "Get all user-level webhook targets", + "responses": { + "200": { + "description": "The list of webhook targets", + "schema": { + "type": "array", + "items": { + "$ref": "#/definitions/models.Webhook" + } + } + }, + "500": { + "description": "Internal server error", + "schema": { + "$ref": "#/definitions/models.Message" + } + } + } + }, + "put": { + "security": [ + { + "JWTKeyAuth": [] + } + ], + "description": "Create a webhook target for the current user that receives events across all projects.", + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "webhooks" + ], + "summary": "Create a user-level webhook target", + "parameters": [ + { + "description": "The webhook target", + "name": "webhook", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/models.Webhook" + } + } + ], + "responses": { + "200": { + "description": "The created webhook target", + "schema": { + "$ref": "#/definitions/models.Webhook" + } + }, + "400": { + "description": "Invalid webhook", + "schema": { + "$ref": "#/definitions/web.HTTPError" + } + }, + "500": { + "description": "Internal server error", + "schema": { + "$ref": "#/definitions/models.Message" + } + } + } + } + }, + "/user/settings/webhooks/events": { + "get": { + "security": [ + { + "JWTKeyAuth": [] + } + ], + "description": "Get all webhook events that can be used with user-level webhook targets.", + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "webhooks" + ], + "summary": "Get available user-directed webhook events", + "responses": { + "200": { + "description": "The list of user-directed webhook events", + "schema": { + "type": "array", + "items": { + "type": "string" + } + } + } + } + } + }, + "/user/settings/webhooks/{id}": { + "post": { + "security": [ + { + "JWTKeyAuth": [] + } + ], + "description": "Update the events for a user-level webhook target.", + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "webhooks" + ], + "summary": "Update a user-level webhook target", + "parameters": [ + { + "type": "integer", + "description": "Webhook ID", + "name": "id", + "in": "path", + "required": true + } + ], + "responses": { + "200": { + "description": "The updated webhook target", + "schema": { + "$ref": "#/definitions/models.Webhook" + } + }, + "404": { + "description": "Webhook not found", + "schema": { + "$ref": "#/definitions/web.HTTPError" + } + }, + "500": { + "description": "Internal server error", + "schema": { + "$ref": "#/definitions/models.Message" + } + } + } + }, + "delete": { + "security": [ + { + "JWTKeyAuth": [] + } + ], + "description": "Delete a user-level webhook target.", + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "webhooks" + ], + "summary": "Delete a user-level webhook target", + "parameters": [ + { + "type": "integer", + "description": "Webhook ID", + "name": "id", + "in": "path", + "required": true + } + ], + "responses": { + "200": { + "description": "Successfully deleted", + "schema": { + "$ref": "#/definitions/models.Message" + } + }, + "404": { + "description": "Webhook not found", + "schema": { + "$ref": "#/definitions/web.HTTPError" + } + }, + "500": { + "description": "Internal server error", + "schema": { + "$ref": "#/definitions/models.Message" + } + } + } + } + }, "/user/timezones": { "get": { "security": [ @@ -9379,6 +9592,10 @@ "updated": { "description": "A timestamp when this webhook target was last updated. You cannot change this value.", "type": "string" + }, + "user_id": { + "description": "The user ID if this is a user-level webhook (mutually exclusive with ProjectID)", + "type": "integer" } } }, diff --git a/pkg/swagger/swagger.yaml b/pkg/swagger/swagger.yaml index 111ff6b8c..3669f72b7 100644 --- a/pkg/swagger/swagger.yaml +++ b/pkg/swagger/swagger.yaml @@ -1148,6 +1148,10 @@ definitions: description: A timestamp when this webhook target was last updated. You cannot change this value. type: string + user_id: + description: The user ID if this is a user-level webhook (mutually exclusive + with ProjectID) + type: integer type: object notifications.DatabaseNotification: properties: @@ -6650,6 +6654,142 @@ paths: summary: Totp QR Code tags: - user + /user/settings/webhooks: + get: + consumes: + - application/json + description: Get all webhook targets configured for the current user (not project-specific). + produces: + - application/json + responses: + "200": + description: The list of webhook targets + schema: + items: + $ref: '#/definitions/models.Webhook' + type: array + "500": + description: Internal server error + schema: + $ref: '#/definitions/models.Message' + security: + - JWTKeyAuth: [] + summary: Get all user-level webhook targets + tags: + - webhooks + put: + consumes: + - application/json + description: Create a webhook target for the current user that receives events + across all projects. + parameters: + - description: The webhook target + in: body + name: webhook + required: true + schema: + $ref: '#/definitions/models.Webhook' + produces: + - application/json + responses: + "200": + description: The created webhook target + schema: + $ref: '#/definitions/models.Webhook' + "400": + description: Invalid webhook + schema: + $ref: '#/definitions/web.HTTPError' + "500": + description: Internal server error + schema: + $ref: '#/definitions/models.Message' + security: + - JWTKeyAuth: [] + summary: Create a user-level webhook target + tags: + - webhooks + /user/settings/webhooks/{id}: + delete: + consumes: + - application/json + description: Delete a user-level webhook target. + parameters: + - description: Webhook ID + in: path + name: id + required: true + type: integer + produces: + - application/json + responses: + "200": + description: Successfully deleted + schema: + $ref: '#/definitions/models.Message' + "404": + description: Webhook not found + schema: + $ref: '#/definitions/web.HTTPError' + "500": + description: Internal server error + schema: + $ref: '#/definitions/models.Message' + security: + - JWTKeyAuth: [] + summary: Delete a user-level webhook target + tags: + - webhooks + post: + consumes: + - application/json + description: Update the events for a user-level webhook target. + parameters: + - description: Webhook ID + in: path + name: id + required: true + type: integer + produces: + - application/json + responses: + "200": + description: The updated webhook target + schema: + $ref: '#/definitions/models.Webhook' + "404": + description: Webhook not found + schema: + $ref: '#/definitions/web.HTTPError' + "500": + description: Internal server error + schema: + $ref: '#/definitions/models.Message' + security: + - JWTKeyAuth: [] + summary: Update a user-level webhook target + tags: + - webhooks + /user/settings/webhooks/events: + get: + consumes: + - application/json + description: Get all webhook events that can be used with user-level webhook + targets. + produces: + - application/json + responses: + "200": + description: The list of user-directed webhook events + schema: + items: + type: string + type: array + security: + - JWTKeyAuth: [] + summary: Get available user-directed webhook events + tags: + - webhooks /user/timezones: get: consumes: From 56c94ddb43ce4f45713068bfdd172c8479433656 Mon Sep 17 00:00:00 2001 From: kolaente Date: Mon, 9 Mar 2026 00:27:51 +0100 Subject: [PATCH 042/142] chore(dev): update devenv --- devenv.lock | 46 +++++++++++++++++++++++++++++++++------------- 1 file changed, 33 insertions(+), 13 deletions(-) diff --git a/devenv.lock b/devenv.lock index 7396145e7..6184f1dc8 100644 --- a/devenv.lock +++ b/devenv.lock @@ -3,10 +3,10 @@ "devenv": { "locked": { "dir": "src/modules", - "lastModified": 1766087669, + "lastModified": 1773012232, "owner": "cachix", "repo": "devenv", - "rev": "c03eed645ea94da7afbee29da76436b7ce33a5cb", + "rev": "46a4bd0299a26ad948b71d3053174ba7b90522f7", "type": "github" }, "original": { @@ -19,14 +19,14 @@ "flake-compat": { "flake": false, "locked": { - "lastModified": 1765121682, - "owner": "edolstra", + "lastModified": 1767039857, + "owner": "NixOS", "repo": "flake-compat", - "rev": "65f23138d8d09a92e30f1e5c87611b23ef451bf3", + "rev": "5edf11c44bc78a0d334f6334cdaf7d60d732daab", "type": "github" }, "original": { - "owner": "edolstra", + "owner": "NixOS", "repo": "flake-compat", "type": "github" } @@ -40,10 +40,10 @@ ] }, "locked": { - "lastModified": 1765911976, + "lastModified": 1772893680, "owner": "cachix", "repo": "git-hooks.nix", - "rev": "b68b780b69702a090c8bb1b973bab13756cc7a27", + "rev": "8baab586afc9c9b57645a734c820e4ac0a604af9", "type": "github" }, "original": { @@ -73,11 +73,14 @@ } }, "nixpkgs": { + "inputs": { + "nixpkgs-src": "nixpkgs-src" + }, "locked": { - "lastModified": 1764580874, + "lastModified": 1772749504, "owner": "cachix", "repo": "devenv-nixpkgs", - "rev": "dcf61356c3ab25f1362b4a4428a6d871e84f1d1d", + "rev": "08543693199362c1fddb8f52126030d0d374ba2e", "type": "github" }, "original": { @@ -87,12 +90,29 @@ "type": "github" } }, - "nixpkgs-unstable": { + "nixpkgs-src": { + "flake": false, "locked": { - "lastModified": 1766070988, + "lastModified": 1769922788, + "narHash": "sha256-H3AfG4ObMDTkTJYkd8cz1/RbY9LatN5Mk4UF48VuSXc=", "owner": "NixOS", "repo": "nixpkgs", - "rev": "c6245e83d836d0433170a16eb185cefe0572f8b8", + "rev": "207d15f1a6603226e1e223dc79ac29c7846da32e", + "type": "github" + }, + "original": { + "owner": "NixOS", + "ref": "nixpkgs-unstable", + "repo": "nixpkgs", + "type": "github" + } + }, + "nixpkgs-unstable": { + "locked": { + "lastModified": 1772773019, + "owner": "NixOS", + "repo": "nixpkgs", + "rev": "aca4d95fce4914b3892661bcb80b8087293536c6", "type": "github" }, "original": { From d5f52868c520dbcf0f5b22cb12eb99d9ff5153c2 Mon Sep 17 00:00:00 2001 From: "Frederick [Bot]" Date: Mon, 9 Mar 2026 01:14:37 +0000 Subject: [PATCH 043/142] chore(i18n): update translations via Crowdin --- pkg/i18n/lang/de-DE.json | 5 ----- pkg/i18n/lang/de-swiss.json | 5 ----- pkg/i18n/lang/fi-FI.json | 5 ----- pkg/i18n/lang/fr-FR.json | 5 ----- pkg/i18n/lang/he-IL.json | 1 - pkg/i18n/lang/it-IT.json | 5 ----- pkg/i18n/lang/ja-JP.json | 5 ----- pkg/i18n/lang/ko-KR.json | 5 ----- pkg/i18n/lang/nl-NL.json | 5 ----- pkg/i18n/lang/no-NO.json | 5 ----- pkg/i18n/lang/pt-PT.json | 5 ----- pkg/i18n/lang/ru-RU.json | 5 ----- pkg/i18n/lang/sv-SE.json | 5 ----- pkg/i18n/lang/tr-TR.json | 5 ----- pkg/i18n/lang/vi-VN.json | 3 --- pkg/i18n/lang/zh-CN.json | 5 ----- pkg/i18n/lang/zh-TW.json | 5 ----- 17 files changed, 79 deletions(-) diff --git a/pkg/i18n/lang/de-DE.json b/pkg/i18n/lang/de-DE.json index b5452311d..bfd8479b2 100644 --- a/pkg/i18n/lang/de-DE.json +++ b/pkg/i18n/lang/de-DE.json @@ -71,8 +71,6 @@ "message": "Dies ist eine freundliche Erinnerung an die Aufgabe „%[1]s“ (%[2]s)." }, "comment": { - "subject": "Re: %[1]s", - "mentioned_subject": "%[1]s hat dich in einem Kommentar zu „%[2]s“ erwähnt", "mentioned_message": "**%[1]s** hat dich in einem Kommentar erwähnt:" }, "assigned": { @@ -88,8 +86,6 @@ "message": "%[1]s hat die Aufgabe „%[2]s“ (%[3]s) gelöscht" }, "mentioned": { - "subject_new": "%[1]s hat dich in einer neuen Aufgabe „%[2]s“ erwähnt", - "subject": "%[1]s hat dich in einer Aufgabe „%[2]s“ erwähnt", "message": "**%[1]s** hat dich in einer Aufgabe erwähnt:" }, "overdue": { @@ -137,7 +133,6 @@ "have_nice_day": "Hab einen schönen Tag!", "copy_url": "Falls der Button oben nicht funktioniert, kopiere die untenstehende URL und füge sie in die Adressleiste deines Browsers ein:", "actions": { - "open_task": "Aufgabe öffnen", "open_vikunja": "Vikunja öffnen", "open_project": "Projekt öffnen", "open_team": "Team öffnen", diff --git a/pkg/i18n/lang/de-swiss.json b/pkg/i18n/lang/de-swiss.json index b5452311d..bfd8479b2 100644 --- a/pkg/i18n/lang/de-swiss.json +++ b/pkg/i18n/lang/de-swiss.json @@ -71,8 +71,6 @@ "message": "Dies ist eine freundliche Erinnerung an die Aufgabe „%[1]s“ (%[2]s)." }, "comment": { - "subject": "Re: %[1]s", - "mentioned_subject": "%[1]s hat dich in einem Kommentar zu „%[2]s“ erwähnt", "mentioned_message": "**%[1]s** hat dich in einem Kommentar erwähnt:" }, "assigned": { @@ -88,8 +86,6 @@ "message": "%[1]s hat die Aufgabe „%[2]s“ (%[3]s) gelöscht" }, "mentioned": { - "subject_new": "%[1]s hat dich in einer neuen Aufgabe „%[2]s“ erwähnt", - "subject": "%[1]s hat dich in einer Aufgabe „%[2]s“ erwähnt", "message": "**%[1]s** hat dich in einer Aufgabe erwähnt:" }, "overdue": { @@ -137,7 +133,6 @@ "have_nice_day": "Hab einen schönen Tag!", "copy_url": "Falls der Button oben nicht funktioniert, kopiere die untenstehende URL und füge sie in die Adressleiste deines Browsers ein:", "actions": { - "open_task": "Aufgabe öffnen", "open_vikunja": "Vikunja öffnen", "open_project": "Projekt öffnen", "open_team": "Team öffnen", diff --git a/pkg/i18n/lang/fi-FI.json b/pkg/i18n/lang/fi-FI.json index 1bbd24499..c05811607 100644 --- a/pkg/i18n/lang/fi-FI.json +++ b/pkg/i18n/lang/fi-FI.json @@ -67,13 +67,9 @@ "message": "Tämä on ystävällinen muistutus tehtävästä \"%[1]s\" (%[2]s)." }, "comment": { - "subject": "Re: %[1]s", - "mentioned_subject": "%[1]s mainitsi sinut kommentissa \"%[2]s\"", "mentioned_message": "**%[1]s** mainitsi sinut kommentissa:" }, "mentioned": { - "subject_new": "%[1]s mainitsi sinut uudessa tehtävässä \"%[2]s\"", - "subject": "%[1]s mainitsi sinut tehtävässä \"%[2]s\"", "message": "**%[1]s** mainitsi sinut tehtävässä:" }, "overdue": { @@ -105,7 +101,6 @@ "have_nice_day": "Hauskaa päivän jatkoa!", "copy_url": "Jos yläpuolella oleva nappi ei toimi, kopioi seuraava osoite selaimesi osoitepalkkiin:", "actions": { - "open_task": "Avaa Tehtävä", "open_vikunja": "Avaa Vikunja", "open_project": "Avaa Projekti", "open_team": "Avaa Tiimi", diff --git a/pkg/i18n/lang/fr-FR.json b/pkg/i18n/lang/fr-FR.json index bff72673e..a4767601a 100644 --- a/pkg/i18n/lang/fr-FR.json +++ b/pkg/i18n/lang/fr-FR.json @@ -71,8 +71,6 @@ "message": "Ceci est un petit rappel de la tâche \"%[1]s\" (%[2]s)." }, "comment": { - "subject": "Re: %[1]s", - "mentioned_subject": "%[1]s vous a mentionné dans un commentaire dans \"%[2]s\"", "mentioned_message": "**%[1]s** vous a mentionné dans un commentaire :" }, "assigned": { @@ -86,8 +84,6 @@ "message": "%[1]s a supprimé la tâche \"%[2]s\" (%[3]s)" }, "mentioned": { - "subject_new": "%[1]s vous a mentionné dans une nouvelle tâche \"%[2]", - "subject": "%[1]s vous a mentionné dans une tâche \"%[2]", "message": "**%[1]s** vous a mentionné dans une tâche :" }, "overdue": { @@ -135,7 +131,6 @@ "have_nice_day": "Passez une bonne journée !", "copy_url": "Si le bouton ci-dessus ne fonctionne pas, copiez l'URL ci-dessous et collez-la dans la barre d'adresse de votre navigateur :", "actions": { - "open_task": "Ouvrir la tâche", "open_vikunja": "Ouvrir Vikunja", "open_project": "Ouvrir le projet", "open_team": "Ouvrir l'équipe", diff --git a/pkg/i18n/lang/he-IL.json b/pkg/i18n/lang/he-IL.json index 2db2be49b..99bcb6212 100644 --- a/pkg/i18n/lang/he-IL.json +++ b/pkg/i18n/lang/he-IL.json @@ -31,7 +31,6 @@ }, "common": { "actions": { - "open_task": "פתיחת מטלה", "open_project": "פתיחת פרויקט", "open_team": "פתיחת צוות", "download": "הורדה", diff --git a/pkg/i18n/lang/it-IT.json b/pkg/i18n/lang/it-IT.json index 4470a7fc1..38347d40e 100644 --- a/pkg/i18n/lang/it-IT.json +++ b/pkg/i18n/lang/it-IT.json @@ -71,8 +71,6 @@ "message": "Questo è un promemoria amichevole dell'attività \"%[1]s\" (%[2]s)." }, "comment": { - "subject": "Riguardo a %[1]s", - "mentioned_subject": "%[1]s ti ha menzionato in un commento in \"%[2]s\"", "mentioned_message": "**%[1]s** ti ha menzionato in un commento:" }, "assigned": { @@ -88,8 +86,6 @@ "message": "%[1]s ha eliminato l'attività \"%[2]s\" (%[3]s)" }, "mentioned": { - "subject_new": "%[1]s ti ha menzionato in una nuova attività \"%[2]s\"", - "subject": "%[1]s ti ha menzionato in un'attività \"%[2]s\"", "message": "**%[1]s** ti ha menzionato in un'attività:" }, "overdue": { @@ -137,7 +133,6 @@ "have_nice_day": "Buona giornata!", "copy_url": "Se il pulsante qui sopra non funziona, copia l'Url qui sotto e incollalo nella barra degli indirizzi del tuo browser:", "actions": { - "open_task": "Apri attività", "open_vikunja": "Apri Vikunja", "open_project": "Apri progetto", "open_team": "Apri Squadra", diff --git a/pkg/i18n/lang/ja-JP.json b/pkg/i18n/lang/ja-JP.json index 9bf923bf4..dfc117654 100644 --- a/pkg/i18n/lang/ja-JP.json +++ b/pkg/i18n/lang/ja-JP.json @@ -71,8 +71,6 @@ "message": "タスク「%[1]」(%[2]s) のリマインダーです。" }, "comment": { - "subject": "Re: %[1]s", - "mentioned_subject": "%[1]s が「%[2]」のコメントであなたにメンションしました", "mentioned_message": "**%[1]s** があなたにメンションしました:" }, "assigned": { @@ -88,8 +86,6 @@ "message": "%[1]s がタスク「%[2]」(%[3]s) を削除しました" }, "mentioned": { - "subject_new": "%[1]s が新しいタスク「%[2]」であなたにメンションしました", - "subject": "%[1]s がタスク「%[2]」であなたにメンションしました", "message": "**%[1]s** があなたにメンションしました:" }, "overdue": { @@ -137,7 +133,6 @@ "have_nice_day": "よい一日を!", "copy_url": "上のボタンが機能しない場合は、以下のURLをコピーし、ブラウザのアドレスバーに貼り付けてください:", "actions": { - "open_task": "タスクを開く", "open_vikunja": "Vikunjaを開く", "open_project": "プロジェクトを開く", "open_team": "チームを開く", diff --git a/pkg/i18n/lang/ko-KR.json b/pkg/i18n/lang/ko-KR.json index aca83b219..cdde93021 100644 --- a/pkg/i18n/lang/ko-KR.json +++ b/pkg/i18n/lang/ko-KR.json @@ -71,8 +71,6 @@ "message": "이것은 \"%[1]s\" (%[2]s) 작업에 대한 친절한 알림입니다." }, "comment": { - "subject": "Re: %[1]s", - "mentioned_subject": "%[1]이 \"%[2]s\"의 댓글에서 귀하를 언급했습니다.", "mentioned_message": "**%[1]s** 님이 댓글에서 귀하를 언급했습니다:" }, "assigned": { @@ -86,8 +84,6 @@ "message": "%[1]s 이(가) \"%[2]s\" (%[3]s) 작업을 삭제했습니다." }, "mentioned": { - "subject_new": "%[1]이 새 작업 \"%[2]s\"에서 귀하를 언급했습니다.", - "subject": "%[1]이 “%[2]s”의 작업에서 귀하를 언급했습니다.", "message": "**%[1]s**이(가) 작업에서 사용자를 언급했습니다:" }, "overdue": { @@ -135,7 +131,6 @@ "have_nice_day": "좋은 하루 보내세요!", "copy_url": "위 버튼이 작동하지 않는 경우 아래 URL을 복사하여 브라우저 주소창에 붙여넣으세요:", "actions": { - "open_task": "작업 열기", "open_vikunja": "Vikunja 열기", "open_project": "프로젝트 열기", "open_team": "오픈팀", diff --git a/pkg/i18n/lang/nl-NL.json b/pkg/i18n/lang/nl-NL.json index ce2a88249..0de4efe13 100644 --- a/pkg/i18n/lang/nl-NL.json +++ b/pkg/i18n/lang/nl-NL.json @@ -71,8 +71,6 @@ "message": "Dit is een vriendelijke herinnering voor taak \"%[1]s\" (%[2]s)." }, "comment": { - "subject": "Re: %[1]s", - "mentioned_subject": "%[1]s noemde je in een reactie in \"%[2]s\"", "mentioned_message": "**%[1]s** noemde je in een reactie:" }, "assigned": { @@ -88,8 +86,6 @@ "message": "%[1]s verwijderde taak \"%[2]s\" (%[3]s)" }, "mentioned": { - "subject_new": "%[1]s noemde je in nieuwe taak \"%[2]s\"", - "subject": "%[1]s noemde je in een taak \"%[2]s\"", "message": "**%[1]s** noemde je in een taak:" }, "overdue": { @@ -137,7 +133,6 @@ "have_nice_day": "Fijne dag!", "copy_url": "Als bovenstaande knop niet werkt, kopieer dan onderstaande URL en plak deze in de adresbalk van je browser:", "actions": { - "open_task": "Taak openen", "open_vikunja": "Vikunja openen", "open_project": "Project openen", "open_team": "Team openen", diff --git a/pkg/i18n/lang/no-NO.json b/pkg/i18n/lang/no-NO.json index f4c10ac2b..398bc5564 100644 --- a/pkg/i18n/lang/no-NO.json +++ b/pkg/i18n/lang/no-NO.json @@ -71,8 +71,6 @@ "message": "Dette er en påminnelse om oppgaven «%[1]» (%[2]s)." }, "comment": { - "subject": "Sv: %[1]s", - "mentioned_subject": "%[1]s nevnte deg i en kommentar i \"%[2]s\"", "mentioned_message": "**%[1]s nevnte deg i en kommentar i \"%[]s:" }, "assigned": { @@ -86,8 +84,6 @@ "message": "%[1]s har slettet oppgaven \"%[2]s\" (%[3]s)" }, "mentioned": { - "subject_new": "%[1]s nevnte deg i en kommentar i \"%[2]s\"", - "subject": "%[1]s nevnt deg i en oppgave \"%[2]s\"", "message": "**%[1]s** nevnte deg i en oppgave:" }, "overdue": { @@ -133,7 +129,6 @@ "have_nice_day": "Ha en fin dag!", "copy_url": "Hvis knappen over ikke fungerer, kopier nettadressen under og lim den inn i adresselinjen i nettleseren:", "actions": { - "open_task": "Åpne oppgave", "open_vikunja": "Åpne Vikunja", "open_project": "Åpne prosjekt", "open_team": "Åpne gruppe", diff --git a/pkg/i18n/lang/pt-PT.json b/pkg/i18n/lang/pt-PT.json index a7024c2b2..3394e0dd4 100644 --- a/pkg/i18n/lang/pt-PT.json +++ b/pkg/i18n/lang/pt-PT.json @@ -71,8 +71,6 @@ "message": "Este é um lembrete cordial da tarefa “%[1]s” (%[2]s)." }, "comment": { - "subject": "Re: %[1]s", - "mentioned_subject": "%[1]s mencionou-te num comentário em \"%[2]s\"", "mentioned_message": "**%[1]s** mencionou-te num comentário:" }, "assigned": { @@ -88,8 +86,6 @@ "message": "%[1]s eliminou a tarefa \"%[2]s\" (%[3]s)" }, "mentioned": { - "subject_new": "%[1]s mencionou-te numa nova tarefa \"%[2]s\"", - "subject": "%[1]s mencionou-te numa tarefa \"%[2]s\"", "message": "**%[1]s** mencionou-te numa tarefa:" }, "overdue": { @@ -137,7 +133,6 @@ "have_nice_day": "Tem um ótimo dia!", "copy_url": "Se o botão acima não funcionar, copia o url abaixo e cola-o na barra de endereços do teu browser:", "actions": { - "open_task": "Abrir Tarefa", "open_vikunja": "Abrir Vikunja", "open_project": "Abrir Projeto", "open_team": "Abrir Equipa", diff --git a/pkg/i18n/lang/ru-RU.json b/pkg/i18n/lang/ru-RU.json index f44823aae..6d6aafaed 100644 --- a/pkg/i18n/lang/ru-RU.json +++ b/pkg/i18n/lang/ru-RU.json @@ -71,8 +71,6 @@ "message": "Это напоминание о задаче «%[1]s» (%[2]s)." }, "comment": { - "subject": "Re: %[1]s", - "mentioned_subject": "%[1]s упомянул вас в комментарии в «%[2]s»", "mentioned_message": "Пользователь **%[1]s** упомянул вас в комментарии:" }, "assigned": { @@ -88,8 +86,6 @@ "message": "Пользователь %[1]s удалил задачу «%[2]s» (%[3]s)" }, "mentioned": { - "subject_new": "%[1]s упомянул вас в новой задаче «%[2]s»", - "subject": "%[1]s упомянул вас в задаче «%[2]s»", "message": "Пользователь **%[1]s** упомянул вас в задаче:" }, "overdue": { @@ -136,7 +132,6 @@ "have_nice_day": "Хорошего дня!", "copy_url": "Если ссылка выше не работает, скопируйте и вставьте в адресную строку ссылку отсюда:", "actions": { - "open_task": "Открыть задачу", "open_vikunja": "Открыть Vikunja", "open_project": "Открыть проект", "open_team": "Открыть команду", diff --git a/pkg/i18n/lang/sv-SE.json b/pkg/i18n/lang/sv-SE.json index 2031a1fe1..e3babe3a1 100644 --- a/pkg/i18n/lang/sv-SE.json +++ b/pkg/i18n/lang/sv-SE.json @@ -71,8 +71,6 @@ "message": "Det här är en vänlig påminnelse om uppgiften \"%[1]s\" (%[2])." }, "comment": { - "subject": "Ang: %[1]s", - "mentioned_subject": "%[1]s nämnde dig i en kommentar i \"%[2]s\"", "mentioned_message": "**%[1]s** nämnde dig i en kommentar:" }, "assigned": { @@ -88,8 +86,6 @@ "message": "%[1]s har raderat uppgiften \"%[2]s\" (%[3]s)" }, "mentioned": { - "subject_new": "%[1]s nämnde dig i en ny uppgift \"%[2]s\"", - "subject": "%[1]s nämnde dig i en uppgift \"%[2]s\"", "message": "**%[1]s** nämnde dig i en uppgift:" }, "overdue": { @@ -137,7 +133,6 @@ "have_nice_day": "Ha en trevlig dag!", "copy_url": "Om knappen ovan inte fungerar, kopiera URL:en nedan och klistra in den i webbläsarens adressfält:", "actions": { - "open_task": "Öppna uppgift", "open_vikunja": "Öppna Vikunja", "open_project": "Öppna projekt", "open_team": "Öppna team", diff --git a/pkg/i18n/lang/tr-TR.json b/pkg/i18n/lang/tr-TR.json index 63f5f78c9..98c895e0b 100644 --- a/pkg/i18n/lang/tr-TR.json +++ b/pkg/i18n/lang/tr-TR.json @@ -71,8 +71,6 @@ "message": "Bu, \"%[1]s\" (%[2]s) görevi için dostça bir hatırlatmadır." }, "comment": { - "subject": "Ynt: %[1]s", - "mentioned_subject": "%[1]s, \"%[2]s\" yorumunda sizden bahsetti", "mentioned_message": "**%[1]s**, bir yorumda sizden bahsetti:" }, "assigned": { @@ -88,8 +86,6 @@ "message": "%[1]s, \"%[2]s\" (%[3]s) görevini sildi" }, "mentioned": { - "subject_new": "%[1]s, yeni bir görev olan \"%[2]s\" içinde sizden bahsetti", - "subject": "%[1]s, \"%[2]s\" görevinde sizden bahsetti", "message": "**%[1]s**, bir görevde sizden bahsetti:" }, "overdue": { @@ -137,7 +133,6 @@ "have_nice_day": "İyi günler dileriz!", "copy_url": "Yukarıdaki düğme çalışmazsa, aşağıdaki URL'yi kopyalayıp tarayıcınızın adres çubuğuna yapıştırın:", "actions": { - "open_task": "Görevi Aç", "open_vikunja": "Vikunja'yı Aç", "open_project": "Projeyi Aç", "open_team": "Takımı Aç", diff --git a/pkg/i18n/lang/vi-VN.json b/pkg/i18n/lang/vi-VN.json index 0cca2660f..5c87e541a 100644 --- a/pkg/i18n/lang/vi-VN.json +++ b/pkg/i18n/lang/vi-VN.json @@ -70,15 +70,12 @@ "subject": "Nhắc nhở cho \"%[1]s\" (%[2]s)" }, "comment": { - "mentioned_subject": "%[1]s đã nhắc đến bạn trong một bình luận của \"%[2]s\"", "mentioned_message": "**%[1]s** đã nhắc đến bạn trong một bình luận:" }, "assigned": { "message_to_others": "%[1]s đã giao tác vụ này cho %[2]s." }, "mentioned": { - "subject_new": "%[1]s nhắc đến bạn trong một tác vụ mới \"%[2]s\"", - "subject": "%[1]s đã nhắc đến bạn trong một tác vụ \"%[2]s\"", "message": "**%[1]s** đã nhắc đến bạn trong một tác vụ:" }, "overdue": { diff --git a/pkg/i18n/lang/zh-CN.json b/pkg/i18n/lang/zh-CN.json index 0c617bbc8..0bc41291f 100644 --- a/pkg/i18n/lang/zh-CN.json +++ b/pkg/i18n/lang/zh-CN.json @@ -69,8 +69,6 @@ "message": "这是一个友好的提醒任务\"%[1]s\" (%[2]s)。" }, "comment": { - "subject": "回复:%[1]s", - "mentioned_subject": "%[1]s在\"%[2]s\"的评论中提到了你", "mentioned_message": "**%[1]s**在评论中提到了您:" }, "assigned": { @@ -84,8 +82,6 @@ "message": "%[1]s已删除任务\"%[2]s\" (%[3]s)" }, "mentioned": { - "subject_new": "%[1]s在一个新任务\"%[2]s\"中提到了你", - "subject": "%[1]s在任务\"%[2]s\"中提到了你", "message": "**%[1]s** 在任务中提到了您:" }, "overdue": { @@ -132,7 +128,6 @@ "have_nice_day": "祝你有愉快的一天!", "copy_url": "如果上面的按钮无法工作,请复制下面的URL并将其粘贴到您的浏览器地址栏:", "actions": { - "open_task": "打开任务", "open_vikunja": "打开 Vikunja", "open_project": "打开项目", "open_team": "打开团队", diff --git a/pkg/i18n/lang/zh-TW.json b/pkg/i18n/lang/zh-TW.json index 84cf1987a..83787eb46 100644 --- a/pkg/i18n/lang/zh-TW.json +++ b/pkg/i18n/lang/zh-TW.json @@ -71,8 +71,6 @@ "message": "任務「%[1]s」(%[2]s) 提醒。" }, "comment": { - "subject": "Re: %[1]s", - "mentioned_subject": "%[1]s 在「%[2]s」的評論中提到您", "mentioned_message": "**%[1]s** 在評論中提到您:" }, "assigned": { @@ -88,8 +86,6 @@ "message": "%[1]s 已刪除任務「%[2]s」(%[3]s)" }, "mentioned": { - "subject_new": "%[1]s 在新任務「%[2]s」中提到您", - "subject": "%[1]s 在任務「%[2]s」中提到您", "message": "%[1]s 在任務中提到您:" }, "overdue": { @@ -137,7 +133,6 @@ "have_nice_day": "祝您有美好的一天!", "copy_url": "如果上方按鈕無法使用,請將以下網址複製到瀏覽器的網址列中:", "actions": { - "open_task": "開啟任務", "open_vikunja": "開啟 Vikunja", "open_project": "開啟專案", "open_team": "開啟團隊", From d3cbc4fc4fb7d7fe054c4c022656f2b4d5c42bde Mon Sep 17 00:00:00 2001 From: kolaente Date: Mon, 9 Mar 2026 13:30:23 +0100 Subject: [PATCH 044/142] fix: prefer working directory for service.rootpath default When running as a systemd service, the binary is often in /usr/local/bin but WorkingDirectory points to a data directory like /var/lib/vikunja. Previously, rootpath defaulted to the binary's directory, causing Vikunja to attempt creating files/db in /usr/local/bin. Now os.Getwd() is preferred, which respects systemd's WorkingDirectory and is the intuitive default for all deployment scenarios. --- pkg/config/config.go | 42 ++++++++++++++++++--------------------- pkg/config/config_test.go | 34 +++++++++++++++++++++++++++++++ 2 files changed, 53 insertions(+), 23 deletions(-) create mode 100644 pkg/config/config_test.go diff --git a/pkg/config/config.go b/pkg/config/config.go index 6eaab3acd..272d9e0a3 100644 --- a/pkg/config/config.go +++ b/pkg/config/config.go @@ -287,37 +287,33 @@ func (k Key) setDefault(i interface{}) { viper.SetDefault(string(k), i) } -// Tries different methods to figure out the binary folder. -// Copied and adopted from https://github.com/speedata/publisher/commit/3b668668d57edef04ea854d5bbd58f83eb1b799f -func getBinaryDirLocation() string { - // First, check if the standard library gives us the path. This will work 99% of the time. - ex, err := os.Executable() - if err == nil { +// getRootpathLocation determines the default root path for Vikunja data. +// It prefers the current working directory, which respects systemd's +// WorkingDirectory= setting and is the most intuitive default. +// Falls back to the binary's directory if Getwd fails. +func getRootpathLocation() string { + // Prefer working directory — this respects systemd WorkingDirectory= + // and is the intuitive default for most deployment scenarios. + if wd, err := os.Getwd(); err == nil { + return wd + } + + // Fall back to the binary's directory. + if ex, err := os.Executable(); err == nil { return filepath.Dir(ex) } - // Then check if the binary was run with a full path and use that if that's the case. - if strings.Contains(os.Args[0], "/") { - binDir, err := filepath.Abs(filepath.Dir(os.Args[0])) - if err != nil { - log.Fatal(err) - } - return binDir - } - + // Last resort: search $PATH. exeSuffix := "" if runtime.GOOS == "windows" { exeSuffix = ".exe" } - - // All else failing, search for a vikunja binary in the current $PATH. - // This can give wrong results. - exeLocation, err := exec.LookPath("vikunja" + exeSuffix) - if err != nil { - log.Fatal(err) + if exeLocation, err := exec.LookPath("vikunja" + exeSuffix); err == nil { + return filepath.Dir(exeLocation) } - return filepath.Dir(exeLocation) + log.Fatal("Could not determine root path. Set service.rootpath in your config.") + return "" } // InitDefaultConfig sets default config values @@ -339,7 +335,7 @@ func InitDefaultConfig() { ServicePublicURL.setDefault("") ServiceEnableCaldav.setDefault(true) - ServiceRootpath.setDefault(getBinaryDirLocation()) + ServiceRootpath.setDefault(getRootpathLocation()) ServiceMaxItemsPerPage.setDefault(50) ServiceMotd.setDefault("") ServiceEnableLinkSharing.setDefault(true) diff --git a/pkg/config/config_test.go b/pkg/config/config_test.go new file mode 100644 index 000000000..28b7cba12 --- /dev/null +++ b/pkg/config/config_test.go @@ -0,0 +1,34 @@ +// Vikunja is a to-do list application to facilitate your life. +// Copyright 2018-present Vikunja and contributors. All rights reserved. +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU Affero General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU Affero General Public License for more details. +// +// You should have received a copy of the GNU Affero General Public License +// along with this program. If not, see . + +package config + +import ( + "os" + "testing" + + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" +) + +func TestGetRootpathLocation(t *testing.T) { + // The function should return the current working directory + expected, err := os.Getwd() + require.NoError(t, err) + + result := getRootpathLocation() + assert.Equal(t, expected, result) +} From 2a7165aaba736c53be32bb8cf0cf77e6fb7cd501 Mon Sep 17 00:00:00 2001 From: kolaente Date: Mon, 9 Mar 2026 13:31:41 +0100 Subject: [PATCH 045/142] refactor: add centralized ResolvePath for rootpath-relative paths --- pkg/config/config.go | 10 ++++++++++ pkg/config/config_test.go | 41 +++++++++++++++++++++++++++++++++++++++ 2 files changed, 51 insertions(+) diff --git a/pkg/config/config.go b/pkg/config/config.go index 272d9e0a3..bd62d6121 100644 --- a/pkg/config/config.go +++ b/pkg/config/config.go @@ -473,6 +473,16 @@ func InitDefaultConfig() { PluginsDir.setDefault(filepath.Join(ServiceRootpath.GetString(), "plugins")) } +// ResolvePath resolves a path relative to service.rootpath. +// If the path is already absolute, it is returned as-is (cleaned). +// If the path is relative (or empty), it is joined with service.rootpath. +func ResolvePath(p string) string { + if filepath.IsAbs(p) { + return filepath.Clean(p) + } + return filepath.Join(ServiceRootpath.GetString(), p) +} + func GetConfigValueFromFile(configKey string) string { if !strings.HasSuffix(configKey, ".file") { configKey += ".file" diff --git a/pkg/config/config_test.go b/pkg/config/config_test.go index 28b7cba12..b50d68b37 100644 --- a/pkg/config/config_test.go +++ b/pkg/config/config_test.go @@ -32,3 +32,44 @@ func TestGetRootpathLocation(t *testing.T) { result := getRootpathLocation() assert.Equal(t, expected, result) } + +func TestResolvePath(t *testing.T) { + // Save and restore rootpath + original := ServiceRootpath.GetString() + defer ServiceRootpath.Set(original) + ServiceRootpath.Set("/var/lib/vikunja") + + tests := []struct { + name string + input string + expected string + }{ + { + name: "absolute path returned as-is", + input: "/etc/vikunja/config.yml", + expected: "/etc/vikunja/config.yml", + }, + { + name: "relative path joined with rootpath", + input: "files", + expected: "/var/lib/vikunja/files", + }, + { + name: "relative subdir path joined with rootpath", + input: "data/vikunja.db", + expected: "/var/lib/vikunja/data/vikunja.db", + }, + { + name: "empty string returns rootpath", + input: "", + expected: "/var/lib/vikunja", + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + result := ResolvePath(tt.input) + assert.Equal(t, tt.expected, result) + }) + } +} From a043940e14f686faa15339ecc06f91dd191d22d1 Mon Sep 17 00:00:00 2001 From: kolaente Date: Mon, 9 Mar 2026 13:33:16 +0100 Subject: [PATCH 046/142] refactor: use config.ResolvePath for all rootpath-relative paths Replaces ad-hoc path joining in files, config value loading, and default config values with the centralized ResolvePath function. --- pkg/config/config.go | 10 ++++------ pkg/files/filehandling.go | 8 +------- 2 files changed, 5 insertions(+), 13 deletions(-) diff --git a/pkg/config/config.go b/pkg/config/config.go index bd62d6121..06c032e8d 100644 --- a/pkg/config/config.go +++ b/pkg/config/config.go @@ -379,7 +379,7 @@ func InitDefaultConfig() { DatabaseUser.setDefault("vikunja") DatabasePassword.setDefault("") DatabaseDatabase.setDefault("vikunja") - DatabasePath.setDefault(filepath.Join(ServiceRootpath.GetString(), "vikunja.db")) + DatabasePath.setDefault(ResolvePath("vikunja.db")) DatabaseMaxOpenConnections.setDefault(100) DatabaseMaxIdleConnections.setDefault(50) DatabaseMaxConnectionLifetime.setDefault(10000) @@ -415,7 +415,7 @@ func InitDefaultConfig() { LogDatabase.setDefault("off") LogDatabaseLevel.setDefault("WARNING") LogHTTP.setDefault("stdout") - LogPath.setDefault(ServiceRootpath.GetString() + "/logs") + LogPath.setDefault(ResolvePath("logs")) LogEvents.setDefault("off") LogEventsLevel.setDefault("INFO") LogMail.setDefault("off") @@ -470,7 +470,7 @@ func InitDefaultConfig() { AutoTLSRenewBefore.setDefault("720h") // 30days in hours // Plugins PluginsEnabled.setDefault(false) - PluginsDir.setDefault(filepath.Join(ServiceRootpath.GetString(), "plugins")) + PluginsDir.setDefault(ResolvePath("plugins")) } // ResolvePath resolves a path relative to service.rootpath. @@ -492,9 +492,7 @@ func GetConfigValueFromFile(configKey string) string { return "" } - if !strings.HasPrefix(valuePath, "/") { - valuePath = path.Join(ServiceRootpath.GetString(), valuePath) - } + valuePath = ResolvePath(valuePath) contents, err := os.ReadFile(valuePath) if err == nil { diff --git a/pkg/files/filehandling.go b/pkg/files/filehandling.go index 6cd81d568..51955ca59 100644 --- a/pkg/files/filehandling.go +++ b/pkg/files/filehandling.go @@ -23,7 +23,6 @@ import ( "fmt" "os" "path/filepath" - "strings" "testing" "time" @@ -55,12 +54,7 @@ var s3Client s3PutObjectClient var s3Bucket string func setDefaultLocalConfig() { - if !strings.HasPrefix(config.FilesBasePath.GetString(), "/") { - config.FilesBasePath.Set(filepath.Join( - config.ServiceRootpath.GetString(), - config.FilesBasePath.GetString(), - )) - } + config.FilesBasePath.Set(config.ResolvePath(config.FilesBasePath.GetString())) } // initS3FileHandler initializes the S3 file backend From ddfc565c614761d3dda037902c8309bf5a27fdd1 Mon Sep 17 00:00:00 2001 From: kolaente Date: Mon, 9 Mar 2026 13:35:29 +0100 Subject: [PATCH 047/142] docs: update rootpath description to mention working directory default --- config-raw.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/config-raw.json b/config-raw.json index 35e9f1148..b91c006f7 100644 --- a/config-raw.json +++ b/config-raw.json @@ -46,7 +46,7 @@ { "key": "rootpath", "default_value": "\u003crootpath\u003e", - "comment": "The base path on the file system where the binary and assets are.\nVikunja will also look in this path for a config file, so you could provide only this variable to point to a folder\nwith a config file which will then be used." + "comment": "The base path on the file system where Vikunja stores its data (database, files, logs, plugins).\nDefaults to the current working directory. When running as a systemd service, this respects the WorkingDirectory= setting.\nVikunja will also look in this path for a config file, so you could provide only this variable to point to a folder\nwith a config file which will then be used." }, { "key": "maxitemsperpage", From 271da6a2ecf986e3c3bea4d5ebb830c85c7309bc Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Mon, 9 Mar 2026 19:12:49 +0000 Subject: [PATCH 048/142] chore(deps): update dev-dependencies to v8.57.0 --- frontend/package.json | 4 +- frontend/pnpm-lock.yaml | 142 ++++++++++++++++++++++------------------ 2 files changed, 81 insertions(+), 65 deletions(-) diff --git a/frontend/package.json b/frontend/package.json index ce5d747a7..17df524db 100644 --- a/frontend/package.json +++ b/frontend/package.json @@ -116,8 +116,8 @@ "@types/is-touch-device": "1.0.3", "@types/node": "24.12.0", "@types/sortablejs": "1.15.9", - "@typescript-eslint/eslint-plugin": "8.56.1", - "@typescript-eslint/parser": "8.56.1", + "@typescript-eslint/eslint-plugin": "8.57.0", + "@typescript-eslint/parser": "8.57.0", "@vitejs/plugin-vue": "6.0.4", "@vue/eslint-config-typescript": "14.7.0", "@vue/test-utils": "2.4.6", diff --git a/frontend/pnpm-lock.yaml b/frontend/pnpm-lock.yaml index 9407ce315..210bddef7 100644 --- a/frontend/pnpm-lock.yaml +++ b/frontend/pnpm-lock.yaml @@ -205,17 +205,17 @@ importers: specifier: 1.15.9 version: 1.15.9 '@typescript-eslint/eslint-plugin': - specifier: 8.56.1 - version: 8.56.1(@typescript-eslint/parser@8.56.1(eslint@9.39.4(jiti@2.4.2))(typescript@5.9.3))(eslint@9.39.4(jiti@2.4.2))(typescript@5.9.3) + specifier: 8.57.0 + version: 8.57.0(@typescript-eslint/parser@8.57.0(eslint@9.39.4(jiti@2.4.2))(typescript@5.9.3))(eslint@9.39.4(jiti@2.4.2))(typescript@5.9.3) '@typescript-eslint/parser': - specifier: 8.56.1 - version: 8.56.1(eslint@9.39.4(jiti@2.4.2))(typescript@5.9.3) + specifier: 8.57.0 + version: 8.57.0(eslint@9.39.4(jiti@2.4.2))(typescript@5.9.3) '@vitejs/plugin-vue': specifier: 6.0.4 version: 6.0.4(vite@7.3.1(@types/node@24.12.0)(jiti@2.4.2)(lightningcss@1.31.1)(sass-embedded@1.97.3)(sass@1.97.3)(terser@5.31.6)(yaml@2.5.0))(vue@3.5.27(typescript@5.9.3)) '@vue/eslint-config-typescript': specifier: 14.7.0 - version: 14.7.0(eslint-plugin-vue@10.8.0(@typescript-eslint/parser@8.56.1(eslint@9.39.4(jiti@2.4.2))(typescript@5.9.3))(eslint@9.39.4(jiti@2.4.2))(vue-eslint-parser@10.4.0(eslint@9.39.4(jiti@2.4.2))))(eslint@9.39.4(jiti@2.4.2))(typescript@5.9.3) + version: 14.7.0(eslint-plugin-vue@10.8.0(@typescript-eslint/parser@8.57.0(eslint@9.39.4(jiti@2.4.2))(typescript@5.9.3))(eslint@9.39.4(jiti@2.4.2))(vue-eslint-parser@10.4.0(eslint@9.39.4(jiti@2.4.2))))(eslint@9.39.4(jiti@2.4.2))(typescript@5.9.3) '@vue/test-utils': specifier: 2.4.6 version: 2.4.6 @@ -248,7 +248,7 @@ importers: version: 1.5.0(eslint@9.39.4(jiti@2.4.2)) eslint-plugin-vue: specifier: 10.8.0 - version: 10.8.0(@typescript-eslint/parser@8.56.1(eslint@9.39.4(jiti@2.4.2))(typescript@5.9.3))(eslint@9.39.4(jiti@2.4.2))(vue-eslint-parser@10.4.0(eslint@9.39.4(jiti@2.4.2))) + version: 10.8.0(@typescript-eslint/parser@8.57.0(eslint@9.39.4(jiti@2.4.2))(typescript@5.9.3))(eslint@9.39.4(jiti@2.4.2))(vue-eslint-parser@10.4.0(eslint@9.39.4(jiti@2.4.2))) happy-dom: specifier: 20.8.3 version: 20.8.3 @@ -2683,11 +2683,11 @@ packages: eslint: ^8.57.0 || ^9.0.0 || ^10.0.0 typescript: '>=4.8.4 <6.0.0' - '@typescript-eslint/eslint-plugin@8.56.1': - resolution: {integrity: sha512-Jz9ZztpB37dNC+HU2HI28Bs9QXpzCz+y/twHOwhyrIRdbuVDxSytJNDl6z/aAKlaRIwC7y8wJdkBv7FxYGgi0A==} + '@typescript-eslint/eslint-plugin@8.57.0': + resolution: {integrity: sha512-qeu4rTHR3/IaFORbD16gmjq9+rEs9fGKdX0kF6BKSfi+gCuG3RCKLlSBYzn/bGsY9Tj7KE/DAQStbp8AHJGHEQ==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} peerDependencies: - '@typescript-eslint/parser': ^8.56.1 + '@typescript-eslint/parser': ^8.57.0 eslint: ^8.57.0 || ^9.0.0 || ^10.0.0 typescript: '>=4.8.4 <6.0.0' @@ -2698,8 +2698,8 @@ packages: eslint: ^8.57.0 || ^9.0.0 || ^10.0.0 typescript: '>=4.8.4 <6.0.0' - '@typescript-eslint/parser@8.56.1': - resolution: {integrity: sha512-klQbnPAAiGYFyI02+znpBRLyjL4/BrBd0nyWkdC0s/6xFLkXYQ8OoRrSkqacS1ddVxf/LDyODIKbQ5TgKAf/Fg==} + '@typescript-eslint/parser@8.57.0': + resolution: {integrity: sha512-XZzOmihLIr8AD1b9hL9ccNMzEMWt/dE2u7NyTY9jJG6YNiNthaD5XtUHVF2uCXZ15ng+z2hT3MVuxnUYhq6k1g==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} peerDependencies: eslint: ^8.57.0 || ^9.0.0 || ^10.0.0 @@ -2717,8 +2717,8 @@ packages: peerDependencies: typescript: '>=4.8.4 <6.0.0' - '@typescript-eslint/project-service@8.56.1': - resolution: {integrity: sha512-TAdqQTzHNNvlVFfR+hu2PDJrURiwKsUvxFn1M0h95BB8ah5jejas08jUWG4dBA68jDMI988IvtfdAI53JzEHOQ==} + '@typescript-eslint/project-service@8.57.0': + resolution: {integrity: sha512-pR+dK0BlxCLxtWfaKQWtYr7MhKmzqZxuii+ZjuFlZlIGRZm22HnXFqa2eY+90MUz8/i80YJmzFGDUsi8dMOV5w==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} peerDependencies: typescript: '>=4.8.4 <6.0.0' @@ -2731,8 +2731,8 @@ packages: resolution: {integrity: sha512-7UiO/XwMHquH+ZzfVCfUNkIXlp/yQjjnlYUyYz7pfvlK3/EyyN6BK+emDmGNyQLBtLGaYrTAI6KOw8tFucWL2w==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} - '@typescript-eslint/scope-manager@8.56.1': - resolution: {integrity: sha512-YAi4VDKcIZp0O4tz/haYKhmIDZFEUPOreKbfdAN3SzUDMcPhJ8QI99xQXqX+HoUVq8cs85eRKnD+rne2UAnj2w==} + '@typescript-eslint/scope-manager@8.57.0': + resolution: {integrity: sha512-nvExQqAHF01lUM66MskSaZulpPL5pgy5hI5RfrxviLgzZVffB5yYzw27uK/ft8QnKXI2X0LBrHJFr1TaZtAibw==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} '@typescript-eslint/tsconfig-utils@8.49.0': @@ -2753,6 +2753,12 @@ packages: peerDependencies: typescript: '>=4.8.4 <6.0.0' + '@typescript-eslint/tsconfig-utils@8.57.0': + resolution: {integrity: sha512-LtXRihc5ytjJIQEH+xqjB0+YgsV4/tW35XKX3GTZHpWtcC8SPkT/d4tqdf1cKtesryHm2bgp6l555NYcT2NLvA==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + peerDependencies: + typescript: '>=4.8.4 <6.0.0' + '@typescript-eslint/type-utils@8.56.0': resolution: {integrity: sha512-qX2L3HWOU2nuDs6GzglBeuFXviDODreS58tLY/BALPC7iu3Fa+J7EOTwnX9PdNBxUI7Uh0ntP0YWGnxCkXzmfA==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} @@ -2760,8 +2766,8 @@ packages: eslint: ^8.57.0 || ^9.0.0 || ^10.0.0 typescript: '>=4.8.4 <6.0.0' - '@typescript-eslint/type-utils@8.56.1': - resolution: {integrity: sha512-yB/7dxi7MgTtGhZdaHCemf7PuwrHMenHjmzgUW1aJpO+bBU43OycnM3Wn+DdvDO/8zzA9HlhaJ0AUGuvri4oGg==} + '@typescript-eslint/type-utils@8.57.0': + resolution: {integrity: sha512-yjgh7gmDcJ1+TcEg8x3uWQmn8ifvSupnPfjP21twPKrDP/pTHlEQgmKcitzF/rzPSmv7QjJ90vRpN4U+zoUjwQ==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} peerDependencies: eslint: ^8.57.0 || ^9.0.0 || ^10.0.0 @@ -2779,6 +2785,10 @@ packages: resolution: {integrity: sha512-dbMkdIUkIkchgGDIv7KLUpa0Mda4IYjo4IAMJUZ+3xNoUXxMsk9YtKpTHSChRS85o+H9ftm51gsK1dZReY9CVw==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + '@typescript-eslint/types@8.57.0': + resolution: {integrity: sha512-dTLI8PEXhjUC7B9Kre+u0XznO696BhXcTlOn0/6kf1fHaQW8+VjJAVHJ3eTI14ZapTxdkOmc80HblPQLaEeJdg==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + '@typescript-eslint/typescript-estree@8.49.0': resolution: {integrity: sha512-jrLdRuAbPfPIdYNppHJ/D0wN+wwNfJ32YTAm10eJVsFmrVpXQnDWBn8niCSMlWjvml8jsce5E/O+86IQtTbJWA==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} @@ -2791,8 +2801,8 @@ packages: peerDependencies: typescript: '>=4.8.4 <6.0.0' - '@typescript-eslint/typescript-estree@8.56.1': - resolution: {integrity: sha512-qzUL1qgalIvKWAf9C1HpvBjif+Vm6rcT5wZd4VoMb9+Km3iS3Cv9DY6dMRMDtPnwRAFyAi7YXJpTIEXLvdfPxg==} + '@typescript-eslint/typescript-estree@8.57.0': + resolution: {integrity: sha512-m7faHcyVg0BT3VdYTlX8GdJEM7COexXxS6KqGopxdtkQRvBanK377QDHr4W/vIPAR+ah9+B/RclSW5ldVniO1Q==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} peerDependencies: typescript: '>=4.8.4 <6.0.0' @@ -2804,8 +2814,8 @@ packages: eslint: ^8.57.0 || ^9.0.0 || ^10.0.0 typescript: '>=4.8.4 <6.0.0' - '@typescript-eslint/utils@8.56.1': - resolution: {integrity: sha512-HPAVNIME3tABJ61siYlHzSWCGtOoeP2RTIaHXFMPqjrQKCGB9OgUVdiNgH7TJS2JNIQ5qQ4RsAUDuGaGme/KOA==} + '@typescript-eslint/utils@8.57.0': + resolution: {integrity: sha512-5iIHvpD3CZe06riAsbNxxreP+MuYgVUsV0n4bwLH//VJmgtt54sQeY2GszntJ4BjYCpMzrfVh2SBnUQTtys2lQ==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} peerDependencies: eslint: ^8.57.0 || ^9.0.0 || ^10.0.0 @@ -2819,8 +2829,8 @@ packages: resolution: {integrity: sha512-q+SL+b+05Ud6LbEE35qe4A99P+htKTKVbyiNEe45eCbJFyh/HVK9QXwlrbz+Q4L8SOW4roxSVwXYj4DMBT7Ieg==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} - '@typescript-eslint/visitor-keys@8.56.1': - resolution: {integrity: sha512-KiROIzYdEV85YygXw6BI/Dx4fnBlFQu6Mq4QE4MOH9fFnhohw6wX/OAvDY2/C+ut0I3RSPKenvZJIVYqJNkhEw==} + '@typescript-eslint/visitor-keys@8.57.0': + resolution: {integrity: sha512-zm6xx8UT/Xy2oSr2ZXD0pZo7Jx2XsCoID2IUh9YSTFRu7z+WdwYTRk6LhUftm1crwqbuoF6I8zAFeCMw0YjwDg==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} '@ungap/structured-clone@1.3.0': @@ -9252,14 +9262,14 @@ snapshots: transitivePeerDependencies: - supports-color - '@typescript-eslint/eslint-plugin@8.56.1(@typescript-eslint/parser@8.56.1(eslint@9.39.4(jiti@2.4.2))(typescript@5.9.3))(eslint@9.39.4(jiti@2.4.2))(typescript@5.9.3)': + '@typescript-eslint/eslint-plugin@8.57.0(@typescript-eslint/parser@8.57.0(eslint@9.39.4(jiti@2.4.2))(typescript@5.9.3))(eslint@9.39.4(jiti@2.4.2))(typescript@5.9.3)': dependencies: '@eslint-community/regexpp': 4.12.2 - '@typescript-eslint/parser': 8.56.1(eslint@9.39.4(jiti@2.4.2))(typescript@5.9.3) - '@typescript-eslint/scope-manager': 8.56.1 - '@typescript-eslint/type-utils': 8.56.1(eslint@9.39.4(jiti@2.4.2))(typescript@5.9.3) - '@typescript-eslint/utils': 8.56.1(eslint@9.39.4(jiti@2.4.2))(typescript@5.9.3) - '@typescript-eslint/visitor-keys': 8.56.1 + '@typescript-eslint/parser': 8.57.0(eslint@9.39.4(jiti@2.4.2))(typescript@5.9.3) + '@typescript-eslint/scope-manager': 8.57.0 + '@typescript-eslint/type-utils': 8.57.0(eslint@9.39.4(jiti@2.4.2))(typescript@5.9.3) + '@typescript-eslint/utils': 8.57.0(eslint@9.39.4(jiti@2.4.2))(typescript@5.9.3) + '@typescript-eslint/visitor-keys': 8.57.0 eslint: 9.39.4(jiti@2.4.2) ignore: 7.0.5 natural-compare: 1.4.0 @@ -9280,12 +9290,12 @@ snapshots: transitivePeerDependencies: - supports-color - '@typescript-eslint/parser@8.56.1(eslint@9.39.4(jiti@2.4.2))(typescript@5.9.3)': + '@typescript-eslint/parser@8.57.0(eslint@9.39.4(jiti@2.4.2))(typescript@5.9.3)': dependencies: - '@typescript-eslint/scope-manager': 8.56.1 - '@typescript-eslint/types': 8.56.1 - '@typescript-eslint/typescript-estree': 8.56.1(typescript@5.9.3) - '@typescript-eslint/visitor-keys': 8.56.1 + '@typescript-eslint/scope-manager': 8.57.0 + '@typescript-eslint/types': 8.57.0 + '@typescript-eslint/typescript-estree': 8.57.0(typescript@5.9.3) + '@typescript-eslint/visitor-keys': 8.57.0 debug: 4.4.3 eslint: 9.39.4(jiti@2.4.2) typescript: 5.9.3 @@ -9294,8 +9304,8 @@ snapshots: '@typescript-eslint/project-service@8.49.0(typescript@5.9.3)': dependencies: - '@typescript-eslint/tsconfig-utils': 8.56.0(typescript@5.9.3) - '@typescript-eslint/types': 8.56.0 + '@typescript-eslint/tsconfig-utils': 8.56.1(typescript@5.9.3) + '@typescript-eslint/types': 8.56.1 debug: 4.4.3 typescript: 5.9.3 transitivePeerDependencies: @@ -9303,17 +9313,17 @@ snapshots: '@typescript-eslint/project-service@8.56.0(typescript@5.9.3)': dependencies: - '@typescript-eslint/tsconfig-utils': 8.56.0(typescript@5.9.3) - '@typescript-eslint/types': 8.56.0 + '@typescript-eslint/tsconfig-utils': 8.56.1(typescript@5.9.3) + '@typescript-eslint/types': 8.56.1 debug: 4.4.3 typescript: 5.9.3 transitivePeerDependencies: - supports-color - '@typescript-eslint/project-service@8.56.1(typescript@5.9.3)': + '@typescript-eslint/project-service@8.57.0(typescript@5.9.3)': dependencies: - '@typescript-eslint/tsconfig-utils': 8.56.1(typescript@5.9.3) - '@typescript-eslint/types': 8.56.1 + '@typescript-eslint/tsconfig-utils': 8.57.0(typescript@5.9.3) + '@typescript-eslint/types': 8.57.0 debug: 4.4.3 typescript: 5.9.3 transitivePeerDependencies: @@ -9329,10 +9339,10 @@ snapshots: '@typescript-eslint/types': 8.56.0 '@typescript-eslint/visitor-keys': 8.56.0 - '@typescript-eslint/scope-manager@8.56.1': + '@typescript-eslint/scope-manager@8.57.0': dependencies: - '@typescript-eslint/types': 8.56.1 - '@typescript-eslint/visitor-keys': 8.56.1 + '@typescript-eslint/types': 8.57.0 + '@typescript-eslint/visitor-keys': 8.57.0 '@typescript-eslint/tsconfig-utils@8.49.0(typescript@5.9.3)': dependencies: @@ -9346,6 +9356,10 @@ snapshots: dependencies: typescript: 5.9.3 + '@typescript-eslint/tsconfig-utils@8.57.0(typescript@5.9.3)': + dependencies: + typescript: 5.9.3 + '@typescript-eslint/type-utils@8.56.0(eslint@9.39.4(jiti@2.4.2))(typescript@5.9.3)': dependencies: '@typescript-eslint/types': 8.56.0 @@ -9358,11 +9372,11 @@ snapshots: transitivePeerDependencies: - supports-color - '@typescript-eslint/type-utils@8.56.1(eslint@9.39.4(jiti@2.4.2))(typescript@5.9.3)': + '@typescript-eslint/type-utils@8.57.0(eslint@9.39.4(jiti@2.4.2))(typescript@5.9.3)': dependencies: - '@typescript-eslint/types': 8.56.1 - '@typescript-eslint/typescript-estree': 8.56.1(typescript@5.9.3) - '@typescript-eslint/utils': 8.56.1(eslint@9.39.4(jiti@2.4.2))(typescript@5.9.3) + '@typescript-eslint/types': 8.57.0 + '@typescript-eslint/typescript-estree': 8.57.0(typescript@5.9.3) + '@typescript-eslint/utils': 8.57.0(eslint@9.39.4(jiti@2.4.2))(typescript@5.9.3) debug: 4.4.3 eslint: 9.39.4(jiti@2.4.2) ts-api-utils: 2.4.0(typescript@5.9.3) @@ -9376,6 +9390,8 @@ snapshots: '@typescript-eslint/types@8.56.1': {} + '@typescript-eslint/types@8.57.0': {} + '@typescript-eslint/typescript-estree@8.49.0(typescript@5.9.3)': dependencies: '@typescript-eslint/project-service': 8.49.0(typescript@5.9.3) @@ -9406,12 +9422,12 @@ snapshots: transitivePeerDependencies: - supports-color - '@typescript-eslint/typescript-estree@8.56.1(typescript@5.9.3)': + '@typescript-eslint/typescript-estree@8.57.0(typescript@5.9.3)': dependencies: - '@typescript-eslint/project-service': 8.56.1(typescript@5.9.3) - '@typescript-eslint/tsconfig-utils': 8.56.1(typescript@5.9.3) - '@typescript-eslint/types': 8.56.1 - '@typescript-eslint/visitor-keys': 8.56.1 + '@typescript-eslint/project-service': 8.57.0(typescript@5.9.3) + '@typescript-eslint/tsconfig-utils': 8.57.0(typescript@5.9.3) + '@typescript-eslint/types': 8.57.0 + '@typescript-eslint/visitor-keys': 8.57.0 debug: 4.4.3 minimatch: 10.2.4 semver: 7.7.3 @@ -9432,12 +9448,12 @@ snapshots: transitivePeerDependencies: - supports-color - '@typescript-eslint/utils@8.56.1(eslint@9.39.4(jiti@2.4.2))(typescript@5.9.3)': + '@typescript-eslint/utils@8.57.0(eslint@9.39.4(jiti@2.4.2))(typescript@5.9.3)': dependencies: '@eslint-community/eslint-utils': 4.9.1(eslint@9.39.4(jiti@2.4.2)) - '@typescript-eslint/scope-manager': 8.56.1 - '@typescript-eslint/types': 8.56.1 - '@typescript-eslint/typescript-estree': 8.56.1(typescript@5.9.3) + '@typescript-eslint/scope-manager': 8.57.0 + '@typescript-eslint/types': 8.57.0 + '@typescript-eslint/typescript-estree': 8.57.0(typescript@5.9.3) eslint: 9.39.4(jiti@2.4.2) typescript: 5.9.3 transitivePeerDependencies: @@ -9453,9 +9469,9 @@ snapshots: '@typescript-eslint/types': 8.56.0 eslint-visitor-keys: 5.0.0 - '@typescript-eslint/visitor-keys@8.56.1': + '@typescript-eslint/visitor-keys@8.57.0': dependencies: - '@typescript-eslint/types': 8.56.1 + '@typescript-eslint/types': 8.57.0 eslint-visitor-keys: 5.0.0 '@ungap/structured-clone@1.3.0': {} @@ -9612,11 +9628,11 @@ snapshots: '@vue/devtools-shared@8.0.7': {} - '@vue/eslint-config-typescript@14.7.0(eslint-plugin-vue@10.8.0(@typescript-eslint/parser@8.56.1(eslint@9.39.4(jiti@2.4.2))(typescript@5.9.3))(eslint@9.39.4(jiti@2.4.2))(vue-eslint-parser@10.4.0(eslint@9.39.4(jiti@2.4.2))))(eslint@9.39.4(jiti@2.4.2))(typescript@5.9.3)': + '@vue/eslint-config-typescript@14.7.0(eslint-plugin-vue@10.8.0(@typescript-eslint/parser@8.57.0(eslint@9.39.4(jiti@2.4.2))(typescript@5.9.3))(eslint@9.39.4(jiti@2.4.2))(vue-eslint-parser@10.4.0(eslint@9.39.4(jiti@2.4.2))))(eslint@9.39.4(jiti@2.4.2))(typescript@5.9.3)': dependencies: '@typescript-eslint/utils': 8.56.0(eslint@9.39.4(jiti@2.4.2))(typescript@5.9.3) eslint: 9.39.4(jiti@2.4.2) - eslint-plugin-vue: 10.8.0(@typescript-eslint/parser@8.56.1(eslint@9.39.4(jiti@2.4.2))(typescript@5.9.3))(eslint@9.39.4(jiti@2.4.2))(vue-eslint-parser@10.4.0(eslint@9.39.4(jiti@2.4.2))) + eslint-plugin-vue: 10.8.0(@typescript-eslint/parser@8.57.0(eslint@9.39.4(jiti@2.4.2))(typescript@5.9.3))(eslint@9.39.4(jiti@2.4.2))(vue-eslint-parser@10.4.0(eslint@9.39.4(jiti@2.4.2))) fast-glob: 3.3.3 typescript-eslint: 8.56.0(eslint@9.39.4(jiti@2.4.2))(typescript@5.9.3) vue-eslint-parser: 10.4.0(eslint@9.39.4(jiti@2.4.2)) @@ -10541,7 +10557,7 @@ snapshots: module-replacements: 2.11.0 semver: 7.7.3 - eslint-plugin-vue@10.8.0(@typescript-eslint/parser@8.56.1(eslint@9.39.4(jiti@2.4.2))(typescript@5.9.3))(eslint@9.39.4(jiti@2.4.2))(vue-eslint-parser@10.4.0(eslint@9.39.4(jiti@2.4.2))): + eslint-plugin-vue@10.8.0(@typescript-eslint/parser@8.57.0(eslint@9.39.4(jiti@2.4.2))(typescript@5.9.3))(eslint@9.39.4(jiti@2.4.2))(vue-eslint-parser@10.4.0(eslint@9.39.4(jiti@2.4.2))): dependencies: '@eslint-community/eslint-utils': 4.9.1(eslint@9.39.4(jiti@2.4.2)) eslint: 9.39.4(jiti@2.4.2) @@ -10552,7 +10568,7 @@ snapshots: vue-eslint-parser: 10.4.0(eslint@9.39.4(jiti@2.4.2)) xml-name-validator: 4.0.0 optionalDependencies: - '@typescript-eslint/parser': 8.56.1(eslint@9.39.4(jiti@2.4.2))(typescript@5.9.3) + '@typescript-eslint/parser': 8.57.0(eslint@9.39.4(jiti@2.4.2))(typescript@5.9.3) eslint-scope@8.4.0: dependencies: From 06ead58ea3bb366970473d587db82bb36db07887 Mon Sep 17 00:00:00 2001 From: kolaente Date: Mon, 9 Mar 2026 23:35:10 +0100 Subject: [PATCH 049/142] chore: remove feature request issue template Feature requests should be suggested via the forum, not via GitHub issues. The config.yml already directs users to the forum for this. --- .github/ISSUE_TEMPLATE/feature.yml | 35 ------------------------------ 1 file changed, 35 deletions(-) delete mode 100644 .github/ISSUE_TEMPLATE/feature.yml diff --git a/.github/ISSUE_TEMPLATE/feature.yml b/.github/ISSUE_TEMPLATE/feature.yml deleted file mode 100644 index 5d3ad1a52..000000000 --- a/.github/ISSUE_TEMPLATE/feature.yml +++ /dev/null @@ -1,35 +0,0 @@ -name: Feature Request -description: Found something you weren't expecting? Report it here! -type: Feature -body: - - type: markdown - attributes: - value: | - NOTE: If your issue is a security concern, please send an email to security@vikunja.io instead of opening a public issue. [More information about our security policy](https://vikunja.io/contact/#security). - - type: markdown - attributes: - value: | - Please fill out this issue template to request a new feature. - - 1. If you want to report a bug, please use the Bug template. - 2. Please ask questions or configuration/deploy problems on our [Matrix Room](https://matrix.to/#/#vikunja:matrix.org) or forum (https://community.vikunja.io). - 3. Make sure you are using the latest release and take a moment to check that your feature hasn't been requested before. - 4. Please include all relevant information in the feature request to allow users to discuss this fully. - - type: checkboxes - id: searched - attributes: - label: Pre-submission checklist - options: - - label: I have searched for existing open or closed issue reports with the same feature request. - required: true - - type: textarea - id: description - attributes: - label: Description - description: | - Please provide a description of the feature you are looking for. - - type: textarea - id: alternatives - attributes: - label: Which alternatives did you consider using instead? - From 30fccfb058ab8a4cadb3ac0ce07795965853a532 Mon Sep 17 00:00:00 2001 From: "Frederick [Bot]" Date: Tue, 10 Mar 2026 01:08:39 +0000 Subject: [PATCH 050/142] chore(i18n): update translations via Crowdin --- frontend/src/i18n/lang/de-DE.json | 4 ++++ frontend/src/i18n/lang/de-swiss.json | 4 ++++ pkg/i18n/lang/de-DE.json | 14 +++++++++++++- pkg/i18n/lang/de-swiss.json | 14 +++++++++++++- 4 files changed, 34 insertions(+), 2 deletions(-) diff --git a/frontend/src/i18n/lang/de-DE.json b/frontend/src/i18n/lang/de-DE.json index 13b3925e0..d9ffc3084 100644 --- a/frontend/src/i18n/lang/de-DE.json +++ b/frontend/src/i18n/lang/de-DE.json @@ -186,6 +186,10 @@ "backgroundBrightness": { "title": "Hintergrundhelligkeit" }, + "webhooks": { + "title": "Webhook-Benachrichtigungen", + "description": "Konfiguriere Webhook-URLs, um POST-Anfragen zu erhalten, wenn Erinnerungs- oder Fälligkeitsereignisse ausgelöst werden. Diese Webhooks empfangen Ereignisse aus allen deinen Projekten." + }, "apiTokens": { "title": "API-Tokens", "general": "Mit API-Token kannst du die API von Vikunja ohne Login-Daten verwenden.", diff --git a/frontend/src/i18n/lang/de-swiss.json b/frontend/src/i18n/lang/de-swiss.json index 61903a34d..eded3eca7 100644 --- a/frontend/src/i18n/lang/de-swiss.json +++ b/frontend/src/i18n/lang/de-swiss.json @@ -186,6 +186,10 @@ "backgroundBrightness": { "title": "Hintergrundhelligkeit" }, + "webhooks": { + "title": "Webhook-Benachrichtigungen", + "description": "Konfiguriere Webhook-URLs, um POST-Anfragen zu erhalten, wenn Erinnerungs- oder Fälligkeitsereignisse ausgelöst werden. Diese Webhooks empfangen Ereignisse aus allen deinen Projekten." + }, "apiTokens": { "title": "API-Tokens", "general": "Mit API-Token kannst du die API von Vikunja ohne Login-Daten verwenden.", diff --git a/pkg/i18n/lang/de-DE.json b/pkg/i18n/lang/de-DE.json index bfd8479b2..d7f710d04 100644 --- a/pkg/i18n/lang/de-DE.json +++ b/pkg/i18n/lang/de-DE.json @@ -71,6 +71,8 @@ "message": "Dies ist eine freundliche Erinnerung an die Aufgabe „%[1]s“ (%[2]s)." }, "comment": { + "subject": "Re: %[1]s (%[2]s)", + "mentioned_subject": "%[1]s hat dich in einem Kommentar zu „%[2]s“ (%[3]s) erwähnt", "mentioned_message": "**%[1]s** hat dich in einem Kommentar erwähnt:" }, "assigned": { @@ -86,6 +88,8 @@ "message": "%[1]s hat die Aufgabe „%[2]s“ (%[3]s) gelöscht" }, "mentioned": { + "subject_new": "%[1]s hat dich in einer neuen Aufgabe „%[2]s“ (%[3]s) erwähnt", + "subject": "%[1]s hat dich in einer Aufgabe „%[2]s“ (%[3]s) erwähnt", "message": "**%[1]s** hat dich in einer Aufgabe erwähnt:" }, "overdue": { @@ -133,6 +137,7 @@ "have_nice_day": "Hab einen schönen Tag!", "copy_url": "Falls der Button oben nicht funktioniert, kopiere die untenstehende URL und füge sie in die Adressleiste deines Browsers ein:", "actions": { + "open_task": "Aufgabe in Vikunja öffnen", "open_vikunja": "Vikunja öffnen", "open_project": "Projekt öffnen", "open_team": "Team öffnen", @@ -142,7 +147,14 @@ "confirm_email": "E-Mail-Adresse bestätigen", "abort_deletion": "Löschen abbrechen", "confirm_account_deletion": "Löschung meines Accounts bestätigen", - "change_notification_settings_link": "Du kannst deine Benachrichtigungseinstellungen [hier](%[1]s) ändern." + "change_notification_settings_link": "Du kannst deine Benachrichtigungseinstellungen [hier](%[1]s) ändern.", + "left_comment": "%[1]s hat kommentiert", + "mentioned_you_comment": "%[1]s hat dich in einem Kommentar erwähnt", + "mentioned_you": "%[1]s hat dich erwähnt", + "mentioned_you_new_task": "%[1]s hat dich in einer neuen Aufgabe erwähnt", + "assigned_you": "%[1]s hat dich zugewiesen", + "assigned_themselves": "%[1]s hat sich selbst zugewiesen", + "assigned_user": "%[1]s hat %[2]s zugewiesen" } } }, diff --git a/pkg/i18n/lang/de-swiss.json b/pkg/i18n/lang/de-swiss.json index bfd8479b2..d7f710d04 100644 --- a/pkg/i18n/lang/de-swiss.json +++ b/pkg/i18n/lang/de-swiss.json @@ -71,6 +71,8 @@ "message": "Dies ist eine freundliche Erinnerung an die Aufgabe „%[1]s“ (%[2]s)." }, "comment": { + "subject": "Re: %[1]s (%[2]s)", + "mentioned_subject": "%[1]s hat dich in einem Kommentar zu „%[2]s“ (%[3]s) erwähnt", "mentioned_message": "**%[1]s** hat dich in einem Kommentar erwähnt:" }, "assigned": { @@ -86,6 +88,8 @@ "message": "%[1]s hat die Aufgabe „%[2]s“ (%[3]s) gelöscht" }, "mentioned": { + "subject_new": "%[1]s hat dich in einer neuen Aufgabe „%[2]s“ (%[3]s) erwähnt", + "subject": "%[1]s hat dich in einer Aufgabe „%[2]s“ (%[3]s) erwähnt", "message": "**%[1]s** hat dich in einer Aufgabe erwähnt:" }, "overdue": { @@ -133,6 +137,7 @@ "have_nice_day": "Hab einen schönen Tag!", "copy_url": "Falls der Button oben nicht funktioniert, kopiere die untenstehende URL und füge sie in die Adressleiste deines Browsers ein:", "actions": { + "open_task": "Aufgabe in Vikunja öffnen", "open_vikunja": "Vikunja öffnen", "open_project": "Projekt öffnen", "open_team": "Team öffnen", @@ -142,7 +147,14 @@ "confirm_email": "E-Mail-Adresse bestätigen", "abort_deletion": "Löschen abbrechen", "confirm_account_deletion": "Löschung meines Accounts bestätigen", - "change_notification_settings_link": "Du kannst deine Benachrichtigungseinstellungen [hier](%[1]s) ändern." + "change_notification_settings_link": "Du kannst deine Benachrichtigungseinstellungen [hier](%[1]s) ändern.", + "left_comment": "%[1]s hat kommentiert", + "mentioned_you_comment": "%[1]s hat dich in einem Kommentar erwähnt", + "mentioned_you": "%[1]s hat dich erwähnt", + "mentioned_you_new_task": "%[1]s hat dich in einer neuen Aufgabe erwähnt", + "assigned_you": "%[1]s hat dich zugewiesen", + "assigned_themselves": "%[1]s hat sich selbst zugewiesen", + "assigned_user": "%[1]s hat %[2]s zugewiesen" } } }, From f497e8bb6d78f3b01c2a87540e28d7727e17676e Mon Sep 17 00:00:00 2001 From: kolaente Date: Tue, 10 Mar 2026 23:14:18 +0100 Subject: [PATCH 051/142] fix: ensure /tmp is writable by container user in Docker image The scratch-based Docker image copies /tmp from the builder stage with root ownership, but the container runs as UID 1000. SQLite needs a writable temp directory for complex transactions (task position changes, saved filter creation, data export), causing "disk I/O error: permission denied" errors. Closes go-vikunja/vikunja#2316 --- Dockerfile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Dockerfile b/Dockerfile index 4e49f33db..560303236 100644 --- a/Dockerfile +++ b/Dockerfile @@ -50,7 +50,7 @@ WORKDIR /app/vikunja ENTRYPOINT [ "/app/vikunja/vikunja" ] EXPOSE 3456 -COPY --from=apibuilder /tmp /tmp +COPY --from=apibuilder --chown=1000:1000 /tmp /tmp USER 1000 From d196af0503053d00e05afb8d2585a67b229a5144 Mon Sep 17 00:00:00 2001 From: kolaente Date: Tue, 10 Mar 2026 23:18:07 +0100 Subject: [PATCH 052/142] fix: remove debounce from color picker to prevent stale color on save The color picker had a 500ms debounce before propagating the selected color to the parent component. Since all usages save via an explicit button click (not automatically), the debounce only caused a race condition where the model value could be stale when the user clicked Save within 500ms of picking a color. Closes go-vikunja/vikunja#2312 --- frontend/src/components/input/ColorPicker.vue | 9 +-------- 1 file changed, 1 insertion(+), 8 deletions(-) diff --git a/frontend/src/components/input/ColorPicker.vue b/frontend/src/components/input/ColorPicker.vue index 23e0984de..c7128cc97 100644 --- a/frontend/src/components/input/ColorPicker.vue +++ b/frontend/src/components/input/ColorPicker.vue @@ -82,7 +82,6 @@ const DEFAULT_COLORS = [ ] const color = ref('') -const lastChangeTimeout = ref | null>(null) const defaultColors = ref(DEFAULT_COLORS) const colorListID = ref(createRandomID()) @@ -112,13 +111,7 @@ function update(force = false) { return } - if (lastChangeTimeout.value !== null) { - clearTimeout(lastChangeTimeout.value) - } - - lastChangeTimeout.value = setTimeout(() => { - model.value = color.value - }, 500) + model.value = color.value } function reset() { From 79a612aa5d95f89cd84148295146a92ccddefa74 Mon Sep 17 00:00:00 2001 From: kolaente Date: Tue, 10 Mar 2026 23:37:29 +0100 Subject: [PATCH 053/142] fix: send account deletion notification before deleting user row MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit When deleting a user via CLI (`vikunja user delete -n`), the user row was deleted first, then `notifications.Notify` was called. But `Notify` calls `User.ShouldNotify()` which queries the database to check the user's status — and since the row was already deleted within the same transaction, it returned `ErrUserDoesNotExist`. Move the notification call before the `DELETE` so the user row still exists when `ShouldNotify` checks it. Closes go-vikunja/vikunja#2335 --- pkg/models/user_delete.go | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/pkg/models/user_delete.go b/pkg/models/user_delete.go index 8ccd137e0..f36a5f2f9 100644 --- a/pkg/models/user_delete.go +++ b/pkg/models/user_delete.go @@ -169,14 +169,17 @@ func DeleteUser(s *xorm.Session, u *user.User) (err error) { } } - _, err = s.Where("id = ?", u.ID).Delete(&user.User{}) + // Notify before deleting the user row, because ShouldNotify will try to + // look up the user and fail if the row is already gone. + err = notifications.Notify(u, &user.AccountDeletedNotification{ + User: u, + }, s) if err != nil { return err } - return notifications.Notify(u, &user.AccountDeletedNotification{ - User: u, - }, s) + _, err = s.Where("id = ?", u.ID).Delete(&user.User{}) + return err } func ensureProjectAdminUser(s *xorm.Session, l *Project) (hadUsers bool, err error) { From 675dfb3ea47dd882de7e49ab1b0ace79a5e8bb9b Mon Sep 17 00:00:00 2001 From: kolaente Date: Tue, 10 Mar 2026 23:46:05 +0100 Subject: [PATCH 054/142] test: add web tests for bulk label task endpoint --- pkg/webtests/label_task_test.go | 68 +++++++++++++++++++++++++++++++++ 1 file changed, 68 insertions(+) create mode 100644 pkg/webtests/label_task_test.go diff --git a/pkg/webtests/label_task_test.go b/pkg/webtests/label_task_test.go new file mode 100644 index 000000000..b28511913 --- /dev/null +++ b/pkg/webtests/label_task_test.go @@ -0,0 +1,68 @@ +// Vikunja is a to-do list application to facilitate your life. +// Copyright 2018-present Vikunja and contributors. All rights reserved. +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU Affero General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU Affero General Public License for more details. +// +// You should have received a copy of the GNU Affero General Public License +// along with this program. If not, see . + +package webtests + +import ( + "testing" + + "code.vikunja.io/api/pkg/models" + "code.vikunja.io/api/pkg/web/handler" + + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" +) + +func TestLabelTaskBulk(t *testing.T) { + testHandlerBulk := webHandlerTest{ + user: &testuser1, + strFunc: func() handler.CObject { + return &models.LabelTaskBulk{} + }, + t: t, + } + + t.Run("Create", func(t *testing.T) { + t.Run("Normal", func(t *testing.T) { + rec, err := testHandlerBulk.testCreateWithUser(nil, map[string]string{"projecttask": "1"}, `{"labels":[{"id":1}]}`) + require.NoError(t, err) + assert.Contains(t, rec.Body.String(), `"labels"`) + }) + t.Run("Nonexisting task", func(t *testing.T) { + _, err := testHandlerBulk.testCreateWithUser(nil, map[string]string{"projecttask": "9999"}, `{"labels":[{"id":1}]}`) + require.Error(t, err) + assertHandlerErrorCode(t, err, models.ErrCodeTaskDoesNotExist) + }) + t.Run("Rights check", func(t *testing.T) { + t.Run("Forbidden", func(t *testing.T) { + // Task 34 is owned by user13, user1 has no access + _, err := testHandlerBulk.testCreateWithUser(nil, map[string]string{"projecttask": "34"}, `{"labels":[{"id":1}]}`) + require.Error(t, err) + assert.Contains(t, getHTTPErrorMessage(err), `Forbidden`) + }) + t.Run("Shared Via Team write", func(t *testing.T) { + rec, err := testHandlerBulk.testCreateWithUser(nil, map[string]string{"projecttask": "16"}, `{"labels":[{"id":1}]}`) + require.NoError(t, err) + assert.Contains(t, rec.Body.String(), `"labels"`) + }) + t.Run("Shared Via Team readonly", func(t *testing.T) { + _, err := testHandlerBulk.testCreateWithUser(nil, map[string]string{"projecttask": "15"}, `{"labels":[{"id":1}]}`) + require.Error(t, err) + assert.Contains(t, getHTTPErrorMessage(err), `Forbidden`) + }) + }) + }) +} From 554593cdb6bc0d31a1809c4b969b4fda9423edc3 Mon Sep 17 00:00:00 2001 From: kolaente Date: Tue, 10 Mar 2026 23:47:01 +0100 Subject: [PATCH 055/142] test: add failing test for bulk label API token route registration --- pkg/models/api_routes_test.go | 56 +++++++++++++++++++++++++++++++++++ 1 file changed, 56 insertions(+) create mode 100644 pkg/models/api_routes_test.go diff --git a/pkg/models/api_routes_test.go b/pkg/models/api_routes_test.go new file mode 100644 index 000000000..3dd9e7d99 --- /dev/null +++ b/pkg/models/api_routes_test.go @@ -0,0 +1,56 @@ +// Vikunja is a to-do list application to facilitate your life. +// Copyright 2018-present Vikunja and contributors. All rights reserved. +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU Affero General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU Affero General Public License for more details. +// +// You should have received a copy of the GNU Affero General Public License +// along with this program. If not, see . + +package models + +import ( + "testing" + + "github.com/labstack/echo/v5" + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" +) + +func TestCanDoAPIRoute_BulkLabelTask(t *testing.T) { + // Reset apiTokenRoutes to isolate this test + apiTokenRoutes = make(map[string]APITokenRoute) + + // Register the standard CRUD routes for tasks_labels first + CollectRoutesForAPITokenUsage(echo.RouteInfo{ + Method: "PUT", + Path: "/api/v1/tasks/:projecttask/labels", + }, true) + CollectRoutesForAPITokenUsage(echo.RouteInfo{ + Method: "DELETE", + Path: "/api/v1/tasks/:projecttask/labels/:label", + }, true) + + // Now register the bulk route + CollectRoutesForAPITokenUsage(echo.RouteInfo{ + Method: "POST", + Path: "/api/v1/tasks/:projecttask/labels/bulk", + }, true) + + // Verify that the tasks_labels route group exists + routes, has := apiTokenRoutes["tasks_labels"] + require.True(t, has, "tasks_labels route group should exist") + + // The bulk route should be registered as "update_bulk" under tasks_labels + bulkRoute, has := routes["update_bulk"] + require.True(t, has, "update_bulk should exist in tasks_labels routes") + assert.Equal(t, "/api/v1/tasks/:projecttask/labels/bulk", bulkRoute.Path) + assert.Equal(t, "POST", bulkRoute.Method) +} From e19bea8e3a2804485479748b1c91dc58719dbe11 Mon Sep 17 00:00:00 2001 From: kolaente Date: Tue, 10 Mar 2026 23:49:12 +0100 Subject: [PATCH 056/142] fix: register bulk label route correctly for API token permissions The tasks_labels_bulk route was not recognized as a CRUD route by isStandardCRUDRoute, causing it to be processed as a non-CRUD route and registered in the wrong apiTokenRoutes group. API tokens with tasks_labels permissions could not access the bulk endpoint, resulting in a 401 error. Fixes https://github.com/go-vikunja/vikunja/issues/2375 --- pkg/models/api_routes.go | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/pkg/models/api_routes.go b/pkg/models/api_routes.go index ccb4ee086..5dd7e92e7 100644 --- a/pkg/models/api_routes.go +++ b/pkg/models/api_routes.go @@ -152,6 +152,14 @@ func isStandardCRUDRoute(routeGroupName string, routeParts []string, _ string) b return true } + // Check if this is a bulk variant of a known CRUD resource + if strings.HasSuffix(routeGroupName, "_bulk") { + parent := strings.TrimSuffix(routeGroupName, "_bulk") + if crudResources[parent] { + return true + } + } + // Also check the base resource for nested paths if len(routeParts) > 0 && crudResources[routeParts[0]] { // For single-segment paths, it's CRUD if it's a known resource From c57c884fd49c0f5d615f8e80ae3b62a88dafed6c Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Tue, 10 Mar 2026 23:48:43 +0000 Subject: [PATCH 057/142] chore(deps): update dependency sass-embedded to v1.98.0 --- frontend/package.json | 2 +- frontend/pnpm-lock.yaml | 280 ++++++++++++++++++++-------------------- 2 files changed, 141 insertions(+), 141 deletions(-) diff --git a/frontend/package.json b/frontend/package.json index 17df524db..00fc35f36 100644 --- a/frontend/package.json +++ b/frontend/package.json @@ -138,7 +138,7 @@ "postcss-preset-env": "11.2.0", "rollup": "4.59.0", "rollup-plugin-visualizer": "6.0.11", - "sass-embedded": "1.97.3", + "sass-embedded": "1.98.0", "stylelint": "17.4.0", "stylelint-config-property-sort-order-smacss": "10.0.0", "stylelint-config-recommended-vue": "1.6.1", diff --git a/frontend/pnpm-lock.yaml b/frontend/pnpm-lock.yaml index 210bddef7..34a8f79c8 100644 --- a/frontend/pnpm-lock.yaml +++ b/frontend/pnpm-lock.yaml @@ -176,10 +176,10 @@ importers: version: 10.3.0 '@histoire/plugin-screenshot': specifier: 1.0.0-beta.1 - version: 1.0.0-beta.1(histoire@1.0.0-beta.1(@types/node@24.12.0)(lightningcss@1.31.1)(sass-embedded@1.97.3)(sass@1.97.3)(terser@5.31.6)(vite@7.3.1(@types/node@24.12.0)(jiti@2.4.2)(lightningcss@1.31.1)(sass-embedded@1.97.3)(sass@1.97.3)(terser@5.31.6)(yaml@2.5.0))(yaml@2.5.0))(typescript@5.9.3) + version: 1.0.0-beta.1(histoire@1.0.0-beta.1(@types/node@24.12.0)(lightningcss@1.31.1)(sass-embedded@1.98.0)(sass@1.98.0)(terser@5.31.6)(vite@7.3.1(@types/node@24.12.0)(jiti@2.4.2)(lightningcss@1.31.1)(sass-embedded@1.98.0)(sass@1.98.0)(terser@5.31.6)(yaml@2.5.0))(yaml@2.5.0))(typescript@5.9.3) '@histoire/plugin-vue': specifier: 1.0.0-beta.1 - version: 1.0.0-beta.1(histoire@1.0.0-beta.1(@types/node@24.12.0)(lightningcss@1.31.1)(sass-embedded@1.97.3)(sass@1.97.3)(terser@5.31.6)(vite@7.3.1(@types/node@24.12.0)(jiti@2.4.2)(lightningcss@1.31.1)(sass-embedded@1.97.3)(sass@1.97.3)(terser@5.31.6)(yaml@2.5.0))(yaml@2.5.0))(vite@7.3.1(@types/node@24.12.0)(jiti@2.4.2)(lightningcss@1.31.1)(sass-embedded@1.97.3)(sass@1.97.3)(terser@5.31.6)(yaml@2.5.0))(vue@3.5.27(typescript@5.9.3)) + version: 1.0.0-beta.1(histoire@1.0.0-beta.1(@types/node@24.12.0)(lightningcss@1.31.1)(sass-embedded@1.98.0)(sass@1.98.0)(terser@5.31.6)(vite@7.3.1(@types/node@24.12.0)(jiti@2.4.2)(lightningcss@1.31.1)(sass-embedded@1.98.0)(sass@1.98.0)(terser@5.31.6)(yaml@2.5.0))(yaml@2.5.0))(vite@7.3.1(@types/node@24.12.0)(jiti@2.4.2)(lightningcss@1.31.1)(sass-embedded@1.98.0)(sass@1.98.0)(terser@5.31.6)(yaml@2.5.0))(vue@3.5.27(typescript@5.9.3)) '@playwright/test': specifier: 1.58.2 version: 1.58.2 @@ -188,7 +188,7 @@ importers: version: 3.6.1 '@tailwindcss/vite': specifier: 4.2.1 - version: 4.2.1(vite@7.3.1(@types/node@24.12.0)(jiti@2.4.2)(lightningcss@1.31.1)(sass-embedded@1.97.3)(sass@1.97.3)(terser@5.31.6)(yaml@2.5.0)) + version: 4.2.1(vite@7.3.1(@types/node@24.12.0)(jiti@2.4.2)(lightningcss@1.31.1)(sass-embedded@1.98.0)(sass@1.98.0)(terser@5.31.6)(yaml@2.5.0)) '@tsconfig/node24': specifier: 24.0.4 version: 24.0.4 @@ -212,7 +212,7 @@ importers: version: 8.57.0(eslint@9.39.4(jiti@2.4.2))(typescript@5.9.3) '@vitejs/plugin-vue': specifier: 6.0.4 - version: 6.0.4(vite@7.3.1(@types/node@24.12.0)(jiti@2.4.2)(lightningcss@1.31.1)(sass-embedded@1.97.3)(sass@1.97.3)(terser@5.31.6)(yaml@2.5.0))(vue@3.5.27(typescript@5.9.3)) + version: 6.0.4(vite@7.3.1(@types/node@24.12.0)(jiti@2.4.2)(lightningcss@1.31.1)(sass-embedded@1.98.0)(sass@1.98.0)(terser@5.31.6)(yaml@2.5.0))(vue@3.5.27(typescript@5.9.3)) '@vue/eslint-config-typescript': specifier: 14.7.0 version: 14.7.0(eslint-plugin-vue@10.8.0(@typescript-eslint/parser@8.57.0(eslint@9.39.4(jiti@2.4.2))(typescript@5.9.3))(eslint@9.39.4(jiti@2.4.2))(vue-eslint-parser@10.4.0(eslint@9.39.4(jiti@2.4.2))))(eslint@9.39.4(jiti@2.4.2))(typescript@5.9.3) @@ -254,7 +254,7 @@ importers: version: 20.8.3 histoire: specifier: 1.0.0-beta.1 - version: 1.0.0-beta.1(@types/node@24.12.0)(lightningcss@1.31.1)(sass-embedded@1.97.3)(sass@1.97.3)(terser@5.31.6)(vite@7.3.1(@types/node@24.12.0)(jiti@2.4.2)(lightningcss@1.31.1)(sass-embedded@1.97.3)(sass@1.97.3)(terser@5.31.6)(yaml@2.5.0))(yaml@2.5.0) + version: 1.0.0-beta.1(@types/node@24.12.0)(lightningcss@1.31.1)(sass-embedded@1.98.0)(sass@1.98.0)(terser@5.31.6)(vite@7.3.1(@types/node@24.12.0)(jiti@2.4.2)(lightningcss@1.31.1)(sass-embedded@1.98.0)(sass@1.98.0)(terser@5.31.6)(yaml@2.5.0))(yaml@2.5.0) postcss: specifier: 8.5.8 version: 8.5.8 @@ -271,8 +271,8 @@ importers: specifier: 6.0.11 version: 6.0.11(rollup@4.59.0) sass-embedded: - specifier: 1.97.3 - version: 1.97.3 + specifier: 1.98.0 + version: 1.98.0 stylelint: specifier: 17.4.0 version: 17.4.0(typescript@5.9.3) @@ -299,19 +299,19 @@ importers: version: 3.0.0 vite: specifier: 7.3.1 - version: 7.3.1(@types/node@24.12.0)(jiti@2.4.2)(lightningcss@1.31.1)(sass-embedded@1.97.3)(sass@1.97.3)(terser@5.31.6)(yaml@2.5.0) + version: 7.3.1(@types/node@24.12.0)(jiti@2.4.2)(lightningcss@1.31.1)(sass-embedded@1.98.0)(sass@1.98.0)(terser@5.31.6)(yaml@2.5.0) vite-plugin-pwa: specifier: 1.2.0 - version: 1.2.0(vite@7.3.1(@types/node@24.12.0)(jiti@2.4.2)(lightningcss@1.31.1)(sass-embedded@1.97.3)(sass@1.97.3)(terser@5.31.6)(yaml@2.5.0))(workbox-build@7.4.0)(workbox-window@7.4.0) + version: 1.2.0(vite@7.3.1(@types/node@24.12.0)(jiti@2.4.2)(lightningcss@1.31.1)(sass-embedded@1.98.0)(sass@1.98.0)(terser@5.31.6)(yaml@2.5.0))(workbox-build@7.4.0)(workbox-window@7.4.0) vite-plugin-vue-devtools: specifier: 8.0.7 - version: 8.0.7(vite@7.3.1(@types/node@24.12.0)(jiti@2.4.2)(lightningcss@1.31.1)(sass-embedded@1.97.3)(sass@1.97.3)(terser@5.31.6)(yaml@2.5.0))(vue@3.5.27(typescript@5.9.3)) + version: 8.0.7(vite@7.3.1(@types/node@24.12.0)(jiti@2.4.2)(lightningcss@1.31.1)(sass-embedded@1.98.0)(sass@1.98.0)(terser@5.31.6)(yaml@2.5.0))(vue@3.5.27(typescript@5.9.3)) vite-svg-loader: specifier: 5.1.1 version: 5.1.1(vue@3.5.27(typescript@5.9.3)) vitest: specifier: 4.0.18 - version: 4.0.18(@types/node@24.12.0)(happy-dom@20.8.3)(jiti@2.4.2)(jsdom@27.4.0)(lightningcss@1.31.1)(sass-embedded@1.97.3)(sass@1.97.3)(terser@5.31.6)(yaml@2.5.0) + version: 4.0.18(@types/node@24.12.0)(happy-dom@20.8.3)(jiti@2.4.2)(jsdom@27.4.0)(lightningcss@1.31.1)(sass-embedded@1.98.0)(sass@1.98.0)(terser@5.31.6)(yaml@2.5.0) vue-tsc: specifier: 3.2.5 version: 3.2.5(typescript@5.9.3) @@ -5633,117 +5633,117 @@ packages: safer-buffer@2.1.2: resolution: {integrity: sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==} - sass-embedded-all-unknown@1.97.3: - resolution: {integrity: sha512-t6N46NlPuXiY3rlmG6/+1nwebOBOaLFOOVqNQOC2cJhghOD4hh2kHNQQTorCsbY9S1Kir2la1/XLBwOJfui0xg==} + sass-embedded-all-unknown@1.98.0: + resolution: {integrity: sha512-6n4RyK7/1mhdfYvpP3CClS3fGoYqDvRmLClCESS6I7+SAzqjxvGG6u5Fo+cb1nrPNbbilgbM4QKdgcgWHO9NCA==} cpu: ['!arm', '!arm64', '!riscv64', '!x64'] - sass-embedded-android-arm64@1.97.3: - resolution: {integrity: sha512-aiZ6iqiHsUsaDx0EFbbmmA0QgxicSxVVN3lnJJ0f1RStY0DthUkquGT5RJ4TPdaZ6ebeJWkboV4bra+CP766eA==} + sass-embedded-android-arm64@1.98.0: + resolution: {integrity: sha512-M9Ra98A6vYJHpwhoC/5EuH1eOshQ9ZyNwC8XifUDSbRl/cGeQceT1NReR9wFj3L7s1pIbmes1vMmaY2np0uAKQ==} engines: {node: '>=14.0.0'} cpu: [arm64] os: [android] - sass-embedded-android-arm@1.97.3: - resolution: {integrity: sha512-cRTtf/KV/q0nzGZoUzVkeIVVFv3L/tS1w4WnlHapphsjTXF/duTxI8JOU1c/9GhRPiMdfeXH7vYNcMmtjwX7jg==} + sass-embedded-android-arm@1.98.0: + resolution: {integrity: sha512-LjGiMhHgu7VL1n7EJxTCre1x14bUsWd9d3dnkS2rku003IWOI/fxc7OXgaKagoVzok1kv09rzO3vFXJR5ZeONQ==} engines: {node: '>=14.0.0'} cpu: [arm] os: [android] - sass-embedded-android-riscv64@1.97.3: - resolution: {integrity: sha512-zVEDgl9JJodofGHobaM/q6pNETG69uuBIGQHRo789jloESxxZe82lI3AWJQuPmYCOG5ElfRthqgv89h3gTeLYA==} + sass-embedded-android-riscv64@1.98.0: + resolution: {integrity: sha512-WPe+0NbaJIZE1fq/RfCZANMeIgmy83x4f+SvFOG7LhUthHpZWcOcrPTsCKKmN3xMT3iw+4DXvqTYOCYGRL3hcQ==} engines: {node: '>=14.0.0'} cpu: [riscv64] os: [android] - sass-embedded-android-x64@1.97.3: - resolution: {integrity: sha512-3ke0le7ZKepyXn/dKKspYkpBC0zUk/BMciyP5ajQUDy4qJwobd8zXdAq6kOkdiMB+d9UFJOmEkvgFJHl3lqwcw==} + sass-embedded-android-x64@1.98.0: + resolution: {integrity: sha512-zrD25dT7OHPEgLWuPEByybnIfx4rnCtfge4clBgjZdZ3lF6E7qNLRBtSBmoFflh6Vg0RlEjJo5VlpnTMBM5MQQ==} engines: {node: '>=14.0.0'} cpu: [x64] os: [android] - sass-embedded-darwin-arm64@1.97.3: - resolution: {integrity: sha512-fuqMTqO4gbOmA/kC5b9y9xxNYw6zDEyfOtMgabS7Mz93wimSk2M1quQaTJnL98Mkcsl2j+7shNHxIS/qpcIDDA==} + sass-embedded-darwin-arm64@1.98.0: + resolution: {integrity: sha512-cgr1z9rBnCdMf8K+JabIaYd9Rag2OJi5mjq08XJfbJGMZV/TA6hFJCLGkr5/+ZOn4/geTM5/3aSfQ8z5EIJAOg==} engines: {node: '>=14.0.0'} cpu: [arm64] os: [darwin] - sass-embedded-darwin-x64@1.97.3: - resolution: {integrity: sha512-b/2RBs/2bZpP8lMkyZ0Px0vkVkT8uBd0YXpOwK7iOwYkAT8SsO4+WdVwErsqC65vI5e1e5p1bb20tuwsoQBMVA==} + sass-embedded-darwin-x64@1.98.0: + resolution: {integrity: sha512-OLBOCs/NPeiMqTdOrMFbVHBQFj19GS3bSVSxIhcCq16ZyhouUkYJEZjxQgzv9SWA2q6Ki8GCqp4k6jMeUY9dcA==} engines: {node: '>=14.0.0'} cpu: [x64] os: [darwin] - sass-embedded-linux-arm64@1.97.3: - resolution: {integrity: sha512-IP1+2otCT3DuV46ooxPaOKV1oL5rLjteRzf8ldZtfIEcwhSgSsHgA71CbjYgLEwMY9h4jeal8Jfv3QnedPvSjg==} + sass-embedded-linux-arm64@1.98.0: + resolution: {integrity: sha512-axOE3t2MTBwCtkUCbrdM++Gj0gC0fdHJPrgzQ+q1WUmY9NoNMGqflBtk5mBZaWUeha2qYO3FawxCB8lctFwCtw==} engines: {node: '>=14.0.0'} cpu: [arm64] os: [linux] - sass-embedded-linux-arm@1.97.3: - resolution: {integrity: sha512-2lPQ7HQQg4CKsH18FTsj2hbw5GJa6sBQgDsls+cV7buXlHjqF8iTKhAQViT6nrpLK/e8nFCoaRgSqEC8xMnXuA==} + sass-embedded-linux-arm@1.98.0: + resolution: {integrity: sha512-03baQZCxVyEp8v1NWBRlzGYrmVT/LK7ZrHlF1piscGiGxwfdxoLXVuxsylx3qn/dD/4i/rh7Bzk7reK1br9jvQ==} engines: {node: '>=14.0.0'} cpu: [arm] os: [linux] - sass-embedded-linux-musl-arm64@1.97.3: - resolution: {integrity: sha512-Lij0SdZCsr+mNRSyDZ7XtJpXEITrYsaGbOTz5e6uFLJ9bmzUbV7M8BXz2/cA7bhfpRPT7/lwRKPdV4+aR9Ozcw==} + sass-embedded-linux-musl-arm64@1.98.0: + resolution: {integrity: sha512-LeqNxQA8y4opjhe68CcFvMzCSrBuJqYVFbwElEj9bagHXQHTp9xVPJRn6VcrC+0VLEDq13HVXMv7RslIuU0zmA==} engines: {node: '>=14.0.0'} cpu: [arm64] os: [linux] - sass-embedded-linux-musl-arm@1.97.3: - resolution: {integrity: sha512-cBTMU68X2opBpoYsSZnI321gnoaiMBEtc+60CKCclN6PCL3W3uXm8g4TLoil1hDD6mqU9YYNlVG6sJ+ZNef6Lg==} + sass-embedded-linux-musl-arm@1.98.0: + resolution: {integrity: sha512-OBkjTDPYR4hSaueOGIM6FDpl9nt/VZwbSRpbNu9/eEJcxE8G/vynRugW8KRZmCFjPy8j/jkGBvvS+k9iOqKV3g==} engines: {node: '>=14.0.0'} cpu: [arm] os: [linux] - sass-embedded-linux-musl-riscv64@1.97.3: - resolution: {integrity: sha512-sBeLFIzMGshR4WmHAD4oIM7WJVkSoCIEwutzptFtGlSlwfNiijULp+J5hA2KteGvI6Gji35apR5aWj66wEn/iA==} + sass-embedded-linux-musl-riscv64@1.98.0: + resolution: {integrity: sha512-7w6hSuOHKt8FZsmjRb3iGSxEzM87fO9+M8nt5JIQYMhHTj5C+JY/vcske0v715HCVj5e1xyTnbGXf8FcASeAIw==} engines: {node: '>=14.0.0'} cpu: [riscv64] os: [linux] - sass-embedded-linux-musl-x64@1.97.3: - resolution: {integrity: sha512-/oWJ+OVrDg7ADDQxRLC/4g1+Nsz1g4mkYS2t6XmyMJKFTFK50FVI2t5sOdFH+zmMp+nXHKM036W94y9m4jjEcw==} + sass-embedded-linux-musl-x64@1.98.0: + resolution: {integrity: sha512-QikNyDEJOVqPmxyCFkci8ZdCwEssdItfjQFJB+D+Uy5HFqcS5Lv3d3GxWNX/h1dSb23RPyQdQc267ok5SbEyJw==} engines: {node: '>=14.0.0'} cpu: [x64] os: [linux] - sass-embedded-linux-riscv64@1.97.3: - resolution: {integrity: sha512-l3IfySApLVYdNx0Kjm7Zehte1CDPZVcldma3dZt+TfzvlAEerM6YDgsk5XEj3L8eHBCgHgF4A0MJspHEo2WNfA==} + sass-embedded-linux-riscv64@1.98.0: + resolution: {integrity: sha512-E7fNytc/v4xFBQKzgzBddV/jretA4ULAPO6XmtBiQu4zZBdBozuSxsQLe2+XXeb0X4S2GIl72V7IPABdqke/vA==} engines: {node: '>=14.0.0'} cpu: [riscv64] os: [linux] - sass-embedded-linux-x64@1.97.3: - resolution: {integrity: sha512-Kwqwc/jSSlcpRjULAOVbndqEy2GBzo6OBmmuBVINWUaJLJ8Kczz3vIsDUWLfWz/kTEw9FHBSiL0WCtYLVAXSLg==} + sass-embedded-linux-x64@1.98.0: + resolution: {integrity: sha512-VsvP0t/uw00mMNPv3vwyYKUrFbqzxQHnRMO+bHdAMjvLw4NFf6mscpym9Bzf+NXwi1ZNKnB6DtXjmcpcvqFqYg==} engines: {node: '>=14.0.0'} cpu: [x64] os: [linux] - sass-embedded-unknown-all@1.97.3: - resolution: {integrity: sha512-/GHajyYJmvb0IABUQHbVHf1nuHPtIDo/ClMZ81IDr59wT5CNcMe7/dMNujXwWugtQVGI5UGmqXWZQCeoGnct8Q==} + sass-embedded-unknown-all@1.98.0: + resolution: {integrity: sha512-C4MMzcAo3oEDQnW7L8SBgB9F2Fq5qHPnaYTZRMOH3Mp/7kM4OooBInXpCiiFjLnjY95hzP4KyctVx0uYR6MYlQ==} os: ['!android', '!darwin', '!linux', '!win32'] - sass-embedded-win32-arm64@1.97.3: - resolution: {integrity: sha512-RDGtRS1GVvQfMGAmVXNxYiUOvPzn9oO1zYB/XUM9fudDRnieYTcUytpNTQZLs6Y1KfJxgt5Y+giRceC92fT8Uw==} + sass-embedded-win32-arm64@1.98.0: + resolution: {integrity: sha512-nP/10xbAiPbhQkMr3zQfXE4TuOxPzWRQe1Hgbi90jv2R4TbzbqQTuZVOaJf7KOAN4L2Bo6XCTRjK5XkVnwZuwQ==} engines: {node: '>=14.0.0'} cpu: [arm64] os: [win32] - sass-embedded-win32-x64@1.97.3: - resolution: {integrity: sha512-SFRa2lED9UEwV6vIGeBXeBOLKF+rowF3WmNfb/BzhxmdAsKofCXrJ8ePW7OcDVrvNEbTOGwhsReIsF5sH8fVaw==} + sass-embedded-win32-x64@1.98.0: + resolution: {integrity: sha512-/lbrVsfbcbdZQ5SJCWcV0NVPd6YRs+FtAnfedp4WbCkO/ZO7Zt/58MvI4X2BVpRY/Nt5ZBo1/7v2gYcQ+J4svQ==} engines: {node: '>=14.0.0'} cpu: [x64] os: [win32] - sass-embedded@1.97.3: - resolution: {integrity: sha512-eKzFy13Nk+IRHhlAwP3sfuv+PzOrvzUkwJK2hdoCKYcWGSdmwFpeGpWmyewdw8EgBnsKaSBtgf/0b2K635ecSA==} + sass-embedded@1.98.0: + resolution: {integrity: sha512-Do7u6iRb6K+lrllcTkB1BXcHwOxcKe3rEfOF/GcCLE2w3WpddakRAosJOHFUR37DpsvimQXEt5abs3NzUjEIqg==} engines: {node: '>=16.0.0'} hasBin: true - sass@1.97.3: - resolution: {integrity: sha512-fDz1zJpd5GycprAbu4Q2PV/RprsRtKC/0z82z0JLgdytmcq0+ujJbJ/09bPGDxCLkKY3Np5cRAOcWiVkLXJURg==} + sass@1.98.0: + resolution: {integrity: sha512-+4N/u9dZ4PrgzGgPlKnaaRQx64RO0JBKs9sDhQ2pLgN6JQZ25uPQZKQYaBJU48Kd5BxgXoJ4e09Dq7nMcOUW3A==} engines: {node: '>=14.0.0'} hasBin: true @@ -8281,17 +8281,17 @@ snapshots: dependencies: '@hapi/hoek': 11.0.7 - '@histoire/app@1.0.0-beta.1(vite@7.3.1(@types/node@24.12.0)(jiti@2.4.2)(lightningcss@1.31.1)(sass-embedded@1.97.3)(sass@1.97.3)(terser@5.31.6)(yaml@2.5.0))': + '@histoire/app@1.0.0-beta.1(vite@7.3.1(@types/node@24.12.0)(jiti@2.4.2)(lightningcss@1.31.1)(sass-embedded@1.98.0)(sass@1.98.0)(terser@5.31.6)(yaml@2.5.0))': dependencies: - '@histoire/controls': 1.0.0-beta.1(vite@7.3.1(@types/node@24.12.0)(jiti@2.4.2)(lightningcss@1.31.1)(sass-embedded@1.97.3)(sass@1.97.3)(terser@5.31.6)(yaml@2.5.0)) - '@histoire/shared': 1.0.0-beta.1(vite@7.3.1(@types/node@24.12.0)(jiti@2.4.2)(lightningcss@1.31.1)(sass-embedded@1.97.3)(sass@1.97.3)(terser@5.31.6)(yaml@2.5.0)) + '@histoire/controls': 1.0.0-beta.1(vite@7.3.1(@types/node@24.12.0)(jiti@2.4.2)(lightningcss@1.31.1)(sass-embedded@1.98.0)(sass@1.98.0)(terser@5.31.6)(yaml@2.5.0)) + '@histoire/shared': 1.0.0-beta.1(vite@7.3.1(@types/node@24.12.0)(jiti@2.4.2)(lightningcss@1.31.1)(sass-embedded@1.98.0)(sass@1.98.0)(terser@5.31.6)(yaml@2.5.0)) '@histoire/vendors': 1.0.0-beta.1 fuse.js: 7.1.0 shiki: 3.2.1 transitivePeerDependencies: - vite - '@histoire/controls@1.0.0-beta.1(vite@7.3.1(@types/node@24.12.0)(jiti@2.4.2)(lightningcss@1.31.1)(sass-embedded@1.97.3)(sass@1.97.3)(terser@5.31.6)(yaml@2.5.0))': + '@histoire/controls@1.0.0-beta.1(vite@7.3.1(@types/node@24.12.0)(jiti@2.4.2)(lightningcss@1.31.1)(sass-embedded@1.98.0)(sass@1.98.0)(terser@5.31.6)(yaml@2.5.0))': dependencies: '@codemirror/commands': 6.8.1 '@codemirror/lang-json': 6.0.1 @@ -8300,17 +8300,17 @@ snapshots: '@codemirror/state': 6.5.2 '@codemirror/theme-one-dark': 6.1.2 '@codemirror/view': 6.36.5 - '@histoire/shared': 1.0.0-beta.1(vite@7.3.1(@types/node@24.12.0)(jiti@2.4.2)(lightningcss@1.31.1)(sass-embedded@1.97.3)(sass@1.97.3)(terser@5.31.6)(yaml@2.5.0)) + '@histoire/shared': 1.0.0-beta.1(vite@7.3.1(@types/node@24.12.0)(jiti@2.4.2)(lightningcss@1.31.1)(sass-embedded@1.98.0)(sass@1.98.0)(terser@5.31.6)(yaml@2.5.0)) '@histoire/vendors': 1.0.0-beta.1 transitivePeerDependencies: - vite - '@histoire/plugin-screenshot@1.0.0-beta.1(histoire@1.0.0-beta.1(@types/node@24.12.0)(lightningcss@1.31.1)(sass-embedded@1.97.3)(sass@1.97.3)(terser@5.31.6)(vite@7.3.1(@types/node@24.12.0)(jiti@2.4.2)(lightningcss@1.31.1)(sass-embedded@1.97.3)(sass@1.97.3)(terser@5.31.6)(yaml@2.5.0))(yaml@2.5.0))(typescript@5.9.3)': + '@histoire/plugin-screenshot@1.0.0-beta.1(histoire@1.0.0-beta.1(@types/node@24.12.0)(lightningcss@1.31.1)(sass-embedded@1.98.0)(sass@1.98.0)(terser@5.31.6)(vite@7.3.1(@types/node@24.12.0)(jiti@2.4.2)(lightningcss@1.31.1)(sass-embedded@1.98.0)(sass@1.98.0)(terser@5.31.6)(yaml@2.5.0))(yaml@2.5.0))(typescript@5.9.3)': dependencies: capture-website: 4.2.0(typescript@5.9.3) defu: 6.1.4 fs-extra: 11.2.0 - histoire: 1.0.0-beta.1(@types/node@24.12.0)(lightningcss@1.31.1)(sass-embedded@1.97.3)(sass@1.97.3)(terser@5.31.6)(vite@7.3.1(@types/node@24.12.0)(jiti@2.4.2)(lightningcss@1.31.1)(sass-embedded@1.97.3)(sass@1.97.3)(terser@5.31.6)(yaml@2.5.0))(yaml@2.5.0) + histoire: 1.0.0-beta.1(@types/node@24.12.0)(lightningcss@1.31.1)(sass-embedded@1.98.0)(sass@1.98.0)(terser@5.31.6)(vite@7.3.1(@types/node@24.12.0)(jiti@2.4.2)(lightningcss@1.31.1)(sass-embedded@1.98.0)(sass@1.98.0)(terser@5.31.6)(yaml@2.5.0))(yaml@2.5.0) pathe: 1.1.2 transitivePeerDependencies: - bare-buffer @@ -8319,21 +8319,21 @@ snapshots: - typescript - utf-8-validate - '@histoire/plugin-vue@1.0.0-beta.1(histoire@1.0.0-beta.1(@types/node@24.12.0)(lightningcss@1.31.1)(sass-embedded@1.97.3)(sass@1.97.3)(terser@5.31.6)(vite@7.3.1(@types/node@24.12.0)(jiti@2.4.2)(lightningcss@1.31.1)(sass-embedded@1.97.3)(sass@1.97.3)(terser@5.31.6)(yaml@2.5.0))(yaml@2.5.0))(vite@7.3.1(@types/node@24.12.0)(jiti@2.4.2)(lightningcss@1.31.1)(sass-embedded@1.97.3)(sass@1.97.3)(terser@5.31.6)(yaml@2.5.0))(vue@3.5.27(typescript@5.9.3))': + '@histoire/plugin-vue@1.0.0-beta.1(histoire@1.0.0-beta.1(@types/node@24.12.0)(lightningcss@1.31.1)(sass-embedded@1.98.0)(sass@1.98.0)(terser@5.31.6)(vite@7.3.1(@types/node@24.12.0)(jiti@2.4.2)(lightningcss@1.31.1)(sass-embedded@1.98.0)(sass@1.98.0)(terser@5.31.6)(yaml@2.5.0))(yaml@2.5.0))(vite@7.3.1(@types/node@24.12.0)(jiti@2.4.2)(lightningcss@1.31.1)(sass-embedded@1.98.0)(sass@1.98.0)(terser@5.31.6)(yaml@2.5.0))(vue@3.5.27(typescript@5.9.3))': dependencies: - '@histoire/controls': 1.0.0-beta.1(vite@7.3.1(@types/node@24.12.0)(jiti@2.4.2)(lightningcss@1.31.1)(sass-embedded@1.97.3)(sass@1.97.3)(terser@5.31.6)(yaml@2.5.0)) - '@histoire/shared': 1.0.0-beta.1(vite@7.3.1(@types/node@24.12.0)(jiti@2.4.2)(lightningcss@1.31.1)(sass-embedded@1.97.3)(sass@1.97.3)(terser@5.31.6)(yaml@2.5.0)) + '@histoire/controls': 1.0.0-beta.1(vite@7.3.1(@types/node@24.12.0)(jiti@2.4.2)(lightningcss@1.31.1)(sass-embedded@1.98.0)(sass@1.98.0)(terser@5.31.6)(yaml@2.5.0)) + '@histoire/shared': 1.0.0-beta.1(vite@7.3.1(@types/node@24.12.0)(jiti@2.4.2)(lightningcss@1.31.1)(sass-embedded@1.98.0)(sass@1.98.0)(terser@5.31.6)(yaml@2.5.0)) '@histoire/vendors': 1.0.0-beta.1 change-case: 5.4.4 globby: 14.1.0 - histoire: 1.0.0-beta.1(@types/node@24.12.0)(lightningcss@1.31.1)(sass-embedded@1.97.3)(sass@1.97.3)(terser@5.31.6)(vite@7.3.1(@types/node@24.12.0)(jiti@2.4.2)(lightningcss@1.31.1)(sass-embedded@1.97.3)(sass@1.97.3)(terser@5.31.6)(yaml@2.5.0))(yaml@2.5.0) + histoire: 1.0.0-beta.1(@types/node@24.12.0)(lightningcss@1.31.1)(sass-embedded@1.98.0)(sass@1.98.0)(terser@5.31.6)(vite@7.3.1(@types/node@24.12.0)(jiti@2.4.2)(lightningcss@1.31.1)(sass-embedded@1.98.0)(sass@1.98.0)(terser@5.31.6)(yaml@2.5.0))(yaml@2.5.0) launch-editor: 2.10.0 pathe: 1.1.2 vue: 3.5.27(typescript@5.9.3) transitivePeerDependencies: - vite - '@histoire/shared@1.0.0-beta.1(vite@7.3.1(@types/node@24.12.0)(jiti@2.4.2)(lightningcss@1.31.1)(sass-embedded@1.97.3)(sass@1.97.3)(terser@5.31.6)(yaml@2.5.0))': + '@histoire/shared@1.0.0-beta.1(vite@7.3.1(@types/node@24.12.0)(jiti@2.4.2)(lightningcss@1.31.1)(sass-embedded@1.98.0)(sass@1.98.0)(terser@5.31.6)(yaml@2.5.0))': dependencies: '@histoire/vendors': 1.0.0-beta.1 '@types/fs-extra': 11.0.4 @@ -8341,7 +8341,7 @@ snapshots: chokidar: 4.0.3 pathe: 1.1.2 picocolors: 1.1.1 - vite: 7.3.1(@types/node@24.12.0)(jiti@2.4.2)(lightningcss@1.31.1)(sass-embedded@1.97.3)(sass@1.97.3)(terser@5.31.6)(yaml@2.5.0) + vite: 7.3.1(@types/node@24.12.0)(jiti@2.4.2)(lightningcss@1.31.1)(sass-embedded@1.98.0)(sass@1.98.0)(terser@5.31.6)(yaml@2.5.0) '@histoire/vendors@1.0.0-beta.1': {} @@ -8956,12 +8956,12 @@ snapshots: '@tailwindcss/oxide-win32-arm64-msvc': 4.2.1 '@tailwindcss/oxide-win32-x64-msvc': 4.2.1 - '@tailwindcss/vite@4.2.1(vite@7.3.1(@types/node@24.12.0)(jiti@2.4.2)(lightningcss@1.31.1)(sass-embedded@1.97.3)(sass@1.97.3)(terser@5.31.6)(yaml@2.5.0))': + '@tailwindcss/vite@4.2.1(vite@7.3.1(@types/node@24.12.0)(jiti@2.4.2)(lightningcss@1.31.1)(sass-embedded@1.98.0)(sass@1.98.0)(terser@5.31.6)(yaml@2.5.0))': dependencies: '@tailwindcss/node': 4.2.1 '@tailwindcss/oxide': 4.2.1 tailwindcss: 4.2.1 - vite: 7.3.1(@types/node@24.12.0)(jiti@2.4.2)(lightningcss@1.31.1)(sass-embedded@1.97.3)(sass@1.97.3)(terser@5.31.6)(yaml@2.5.0) + vite: 7.3.1(@types/node@24.12.0)(jiti@2.4.2)(lightningcss@1.31.1)(sass-embedded@1.98.0)(sass@1.98.0)(terser@5.31.6)(yaml@2.5.0) '@tiptap/core@3.17.0(@tiptap/pm@3.17.0)': dependencies: @@ -9476,10 +9476,10 @@ snapshots: '@ungap/structured-clone@1.3.0': {} - '@vitejs/plugin-vue@6.0.4(vite@7.3.1(@types/node@24.12.0)(jiti@2.4.2)(lightningcss@1.31.1)(sass-embedded@1.97.3)(sass@1.97.3)(terser@5.31.6)(yaml@2.5.0))(vue@3.5.27(typescript@5.9.3))': + '@vitejs/plugin-vue@6.0.4(vite@7.3.1(@types/node@24.12.0)(jiti@2.4.2)(lightningcss@1.31.1)(sass-embedded@1.98.0)(sass@1.98.0)(terser@5.31.6)(yaml@2.5.0))(vue@3.5.27(typescript@5.9.3))': dependencies: '@rolldown/pluginutils': 1.0.0-rc.2 - vite: 7.3.1(@types/node@24.12.0)(jiti@2.4.2)(lightningcss@1.31.1)(sass-embedded@1.97.3)(sass@1.97.3)(terser@5.31.6)(yaml@2.5.0) + vite: 7.3.1(@types/node@24.12.0)(jiti@2.4.2)(lightningcss@1.31.1)(sass-embedded@1.98.0)(sass@1.98.0)(terser@5.31.6)(yaml@2.5.0) vue: 3.5.27(typescript@5.9.3) '@vitest/expect@4.0.18': @@ -9491,13 +9491,13 @@ snapshots: chai: 6.2.2 tinyrainbow: 3.0.3 - '@vitest/mocker@4.0.18(vite@7.3.1(@types/node@24.12.0)(jiti@2.4.2)(lightningcss@1.31.1)(sass-embedded@1.97.3)(sass@1.97.3)(terser@5.31.6)(yaml@2.5.0))': + '@vitest/mocker@4.0.18(vite@7.3.1(@types/node@24.12.0)(jiti@2.4.2)(lightningcss@1.31.1)(sass-embedded@1.98.0)(sass@1.98.0)(terser@5.31.6)(yaml@2.5.0))': dependencies: '@vitest/spy': 4.0.18 estree-walker: 3.0.3 magic-string: 0.30.21 optionalDependencies: - vite: 7.3.1(@types/node@24.12.0)(jiti@2.4.2)(lightningcss@1.31.1)(sass-embedded@1.97.3)(sass@1.97.3)(terser@5.31.6)(yaml@2.5.0) + vite: 7.3.1(@types/node@24.12.0)(jiti@2.4.2)(lightningcss@1.31.1)(sass-embedded@1.98.0)(sass@1.98.0)(terser@5.31.6)(yaml@2.5.0) '@vitest/pretty-format@4.0.18': dependencies: @@ -11030,12 +11030,12 @@ snapshots: highlight.js@11.11.1: {} - histoire@1.0.0-beta.1(@types/node@24.12.0)(lightningcss@1.31.1)(sass-embedded@1.97.3)(sass@1.97.3)(terser@5.31.6)(vite@7.3.1(@types/node@24.12.0)(jiti@2.4.2)(lightningcss@1.31.1)(sass-embedded@1.97.3)(sass@1.97.3)(terser@5.31.6)(yaml@2.5.0))(yaml@2.5.0): + histoire@1.0.0-beta.1(@types/node@24.12.0)(lightningcss@1.31.1)(sass-embedded@1.98.0)(sass@1.98.0)(terser@5.31.6)(vite@7.3.1(@types/node@24.12.0)(jiti@2.4.2)(lightningcss@1.31.1)(sass-embedded@1.98.0)(sass@1.98.0)(terser@5.31.6)(yaml@2.5.0))(yaml@2.5.0): dependencies: '@akryum/tinypool': 0.3.1 - '@histoire/app': 1.0.0-beta.1(vite@7.3.1(@types/node@24.12.0)(jiti@2.4.2)(lightningcss@1.31.1)(sass-embedded@1.97.3)(sass@1.97.3)(terser@5.31.6)(yaml@2.5.0)) - '@histoire/controls': 1.0.0-beta.1(vite@7.3.1(@types/node@24.12.0)(jiti@2.4.2)(lightningcss@1.31.1)(sass-embedded@1.97.3)(sass@1.97.3)(terser@5.31.6)(yaml@2.5.0)) - '@histoire/shared': 1.0.0-beta.1(vite@7.3.1(@types/node@24.12.0)(jiti@2.4.2)(lightningcss@1.31.1)(sass-embedded@1.97.3)(sass@1.97.3)(terser@5.31.6)(yaml@2.5.0)) + '@histoire/app': 1.0.0-beta.1(vite@7.3.1(@types/node@24.12.0)(jiti@2.4.2)(lightningcss@1.31.1)(sass-embedded@1.98.0)(sass@1.98.0)(terser@5.31.6)(yaml@2.5.0)) + '@histoire/controls': 1.0.0-beta.1(vite@7.3.1(@types/node@24.12.0)(jiti@2.4.2)(lightningcss@1.31.1)(sass-embedded@1.98.0)(sass@1.98.0)(terser@5.31.6)(yaml@2.5.0)) + '@histoire/shared': 1.0.0-beta.1(vite@7.3.1(@types/node@24.12.0)(jiti@2.4.2)(lightningcss@1.31.1)(sass-embedded@1.98.0)(sass@1.98.0)(terser@5.31.6)(yaml@2.5.0)) '@histoire/vendors': 1.0.0-beta.1 '@types/markdown-it': 14.1.2 birpc: 0.2.19 @@ -11060,8 +11060,8 @@ snapshots: sade: 1.8.1 shiki: 3.2.1 sirv: 3.0.2 - vite: 7.3.1(@types/node@24.12.0)(jiti@2.4.2)(lightningcss@1.31.1)(sass-embedded@1.97.3)(sass@1.97.3)(terser@5.31.6)(yaml@2.5.0) - vite-node: 3.2.4(@types/node@24.12.0)(jiti@2.4.2)(lightningcss@1.31.1)(sass-embedded@1.97.3)(sass@1.97.3)(terser@5.31.6)(yaml@2.5.0) + vite: 7.3.1(@types/node@24.12.0)(jiti@2.4.2)(lightningcss@1.31.1)(sass-embedded@1.98.0)(sass@1.98.0)(terser@5.31.6)(yaml@2.5.0) + vite-node: 3.2.4(@types/node@24.12.0)(jiti@2.4.2)(lightningcss@1.31.1)(sass-embedded@1.98.0)(sass@1.98.0)(terser@5.31.6)(yaml@2.5.0) transitivePeerDependencies: - '@exodus/crypto' - '@types/node' @@ -12582,65 +12582,65 @@ snapshots: safer-buffer@2.1.2: {} - sass-embedded-all-unknown@1.97.3: + sass-embedded-all-unknown@1.98.0: dependencies: - sass: 1.97.3 + sass: 1.98.0 optional: true - sass-embedded-android-arm64@1.97.3: + sass-embedded-android-arm64@1.98.0: optional: true - sass-embedded-android-arm@1.97.3: + sass-embedded-android-arm@1.98.0: optional: true - sass-embedded-android-riscv64@1.97.3: + sass-embedded-android-riscv64@1.98.0: optional: true - sass-embedded-android-x64@1.97.3: + sass-embedded-android-x64@1.98.0: optional: true - sass-embedded-darwin-arm64@1.97.3: + sass-embedded-darwin-arm64@1.98.0: optional: true - sass-embedded-darwin-x64@1.97.3: + sass-embedded-darwin-x64@1.98.0: optional: true - sass-embedded-linux-arm64@1.97.3: + sass-embedded-linux-arm64@1.98.0: optional: true - sass-embedded-linux-arm@1.97.3: + sass-embedded-linux-arm@1.98.0: optional: true - sass-embedded-linux-musl-arm64@1.97.3: + sass-embedded-linux-musl-arm64@1.98.0: optional: true - sass-embedded-linux-musl-arm@1.97.3: + sass-embedded-linux-musl-arm@1.98.0: optional: true - sass-embedded-linux-musl-riscv64@1.97.3: + sass-embedded-linux-musl-riscv64@1.98.0: optional: true - sass-embedded-linux-musl-x64@1.97.3: + sass-embedded-linux-musl-x64@1.98.0: optional: true - sass-embedded-linux-riscv64@1.97.3: + sass-embedded-linux-riscv64@1.98.0: optional: true - sass-embedded-linux-x64@1.97.3: + sass-embedded-linux-x64@1.98.0: optional: true - sass-embedded-unknown-all@1.97.3: + sass-embedded-unknown-all@1.98.0: dependencies: - sass: 1.97.3 + sass: 1.98.0 optional: true - sass-embedded-win32-arm64@1.97.3: + sass-embedded-win32-arm64@1.98.0: optional: true - sass-embedded-win32-x64@1.97.3: + sass-embedded-win32-x64@1.98.0: optional: true - sass-embedded@1.97.3: + sass-embedded@1.98.0: dependencies: '@bufbuild/protobuf': 2.5.2 colorjs.io: 0.5.2 @@ -12650,26 +12650,26 @@ snapshots: sync-child-process: 1.0.2 varint: 6.0.0 optionalDependencies: - sass-embedded-all-unknown: 1.97.3 - sass-embedded-android-arm: 1.97.3 - sass-embedded-android-arm64: 1.97.3 - sass-embedded-android-riscv64: 1.97.3 - sass-embedded-android-x64: 1.97.3 - sass-embedded-darwin-arm64: 1.97.3 - sass-embedded-darwin-x64: 1.97.3 - sass-embedded-linux-arm: 1.97.3 - sass-embedded-linux-arm64: 1.97.3 - sass-embedded-linux-musl-arm: 1.97.3 - sass-embedded-linux-musl-arm64: 1.97.3 - sass-embedded-linux-musl-riscv64: 1.97.3 - sass-embedded-linux-musl-x64: 1.97.3 - sass-embedded-linux-riscv64: 1.97.3 - sass-embedded-linux-x64: 1.97.3 - sass-embedded-unknown-all: 1.97.3 - sass-embedded-win32-arm64: 1.97.3 - sass-embedded-win32-x64: 1.97.3 + sass-embedded-all-unknown: 1.98.0 + sass-embedded-android-arm: 1.98.0 + sass-embedded-android-arm64: 1.98.0 + sass-embedded-android-riscv64: 1.98.0 + sass-embedded-android-x64: 1.98.0 + sass-embedded-darwin-arm64: 1.98.0 + sass-embedded-darwin-x64: 1.98.0 + sass-embedded-linux-arm: 1.98.0 + sass-embedded-linux-arm64: 1.98.0 + sass-embedded-linux-musl-arm: 1.98.0 + sass-embedded-linux-musl-arm64: 1.98.0 + sass-embedded-linux-musl-riscv64: 1.98.0 + sass-embedded-linux-musl-x64: 1.98.0 + sass-embedded-linux-riscv64: 1.98.0 + sass-embedded-linux-x64: 1.98.0 + sass-embedded-unknown-all: 1.98.0 + sass-embedded-win32-arm64: 1.98.0 + sass-embedded-win32-x64: 1.98.0 - sass@1.97.3: + sass@1.98.0: dependencies: chokidar: 4.0.3 immutable: 5.1.5 @@ -13432,23 +13432,23 @@ snapshots: '@types/unist': 3.0.3 vfile-message: 4.0.2 - vite-dev-rpc@1.1.0(vite@7.3.1(@types/node@24.12.0)(jiti@2.4.2)(lightningcss@1.31.1)(sass-embedded@1.97.3)(sass@1.97.3)(terser@5.31.6)(yaml@2.5.0)): + vite-dev-rpc@1.1.0(vite@7.3.1(@types/node@24.12.0)(jiti@2.4.2)(lightningcss@1.31.1)(sass-embedded@1.98.0)(sass@1.98.0)(terser@5.31.6)(yaml@2.5.0)): dependencies: birpc: 2.6.1 - vite: 7.3.1(@types/node@24.12.0)(jiti@2.4.2)(lightningcss@1.31.1)(sass-embedded@1.97.3)(sass@1.97.3)(terser@5.31.6)(yaml@2.5.0) - vite-hot-client: 2.1.0(vite@7.3.1(@types/node@24.12.0)(jiti@2.4.2)(lightningcss@1.31.1)(sass-embedded@1.97.3)(sass@1.97.3)(terser@5.31.6)(yaml@2.5.0)) + vite: 7.3.1(@types/node@24.12.0)(jiti@2.4.2)(lightningcss@1.31.1)(sass-embedded@1.98.0)(sass@1.98.0)(terser@5.31.6)(yaml@2.5.0) + vite-hot-client: 2.1.0(vite@7.3.1(@types/node@24.12.0)(jiti@2.4.2)(lightningcss@1.31.1)(sass-embedded@1.98.0)(sass@1.98.0)(terser@5.31.6)(yaml@2.5.0)) - vite-hot-client@2.1.0(vite@7.3.1(@types/node@24.12.0)(jiti@2.4.2)(lightningcss@1.31.1)(sass-embedded@1.97.3)(sass@1.97.3)(terser@5.31.6)(yaml@2.5.0)): + vite-hot-client@2.1.0(vite@7.3.1(@types/node@24.12.0)(jiti@2.4.2)(lightningcss@1.31.1)(sass-embedded@1.98.0)(sass@1.98.0)(terser@5.31.6)(yaml@2.5.0)): dependencies: - vite: 7.3.1(@types/node@24.12.0)(jiti@2.4.2)(lightningcss@1.31.1)(sass-embedded@1.97.3)(sass@1.97.3)(terser@5.31.6)(yaml@2.5.0) + vite: 7.3.1(@types/node@24.12.0)(jiti@2.4.2)(lightningcss@1.31.1)(sass-embedded@1.98.0)(sass@1.98.0)(terser@5.31.6)(yaml@2.5.0) - vite-node@3.2.4(@types/node@24.12.0)(jiti@2.4.2)(lightningcss@1.31.1)(sass-embedded@1.97.3)(sass@1.97.3)(terser@5.31.6)(yaml@2.5.0): + vite-node@3.2.4(@types/node@24.12.0)(jiti@2.4.2)(lightningcss@1.31.1)(sass-embedded@1.98.0)(sass@1.98.0)(terser@5.31.6)(yaml@2.5.0): dependencies: cac: 6.7.14 debug: 4.4.3 es-module-lexer: 1.7.0 pathe: 2.0.3 - vite: 7.3.1(@types/node@24.12.0)(jiti@2.4.2)(lightningcss@1.31.1)(sass-embedded@1.97.3)(sass@1.97.3)(terser@5.31.6)(yaml@2.5.0) + vite: 7.3.1(@types/node@24.12.0)(jiti@2.4.2)(lightningcss@1.31.1)(sass-embedded@1.98.0)(sass@1.98.0)(terser@5.31.6)(yaml@2.5.0) transitivePeerDependencies: - '@types/node' - jiti @@ -13463,7 +13463,7 @@ snapshots: - tsx - yaml - vite-plugin-inspect@11.3.3(vite@7.3.1(@types/node@24.12.0)(jiti@2.4.2)(lightningcss@1.31.1)(sass-embedded@1.97.3)(sass@1.97.3)(terser@5.31.6)(yaml@2.5.0)): + vite-plugin-inspect@11.3.3(vite@7.3.1(@types/node@24.12.0)(jiti@2.4.2)(lightningcss@1.31.1)(sass-embedded@1.98.0)(sass@1.98.0)(terser@5.31.6)(yaml@2.5.0)): dependencies: ansis: 4.1.0 debug: 4.4.3 @@ -13473,37 +13473,37 @@ snapshots: perfect-debounce: 2.0.0 sirv: 3.0.2 unplugin-utils: 0.3.0 - vite: 7.3.1(@types/node@24.12.0)(jiti@2.4.2)(lightningcss@1.31.1)(sass-embedded@1.97.3)(sass@1.97.3)(terser@5.31.6)(yaml@2.5.0) - vite-dev-rpc: 1.1.0(vite@7.3.1(@types/node@24.12.0)(jiti@2.4.2)(lightningcss@1.31.1)(sass-embedded@1.97.3)(sass@1.97.3)(terser@5.31.6)(yaml@2.5.0)) + vite: 7.3.1(@types/node@24.12.0)(jiti@2.4.2)(lightningcss@1.31.1)(sass-embedded@1.98.0)(sass@1.98.0)(terser@5.31.6)(yaml@2.5.0) + vite-dev-rpc: 1.1.0(vite@7.3.1(@types/node@24.12.0)(jiti@2.4.2)(lightningcss@1.31.1)(sass-embedded@1.98.0)(sass@1.98.0)(terser@5.31.6)(yaml@2.5.0)) transitivePeerDependencies: - supports-color - vite-plugin-pwa@1.2.0(vite@7.3.1(@types/node@24.12.0)(jiti@2.4.2)(lightningcss@1.31.1)(sass-embedded@1.97.3)(sass@1.97.3)(terser@5.31.6)(yaml@2.5.0))(workbox-build@7.4.0)(workbox-window@7.4.0): + vite-plugin-pwa@1.2.0(vite@7.3.1(@types/node@24.12.0)(jiti@2.4.2)(lightningcss@1.31.1)(sass-embedded@1.98.0)(sass@1.98.0)(terser@5.31.6)(yaml@2.5.0))(workbox-build@7.4.0)(workbox-window@7.4.0): dependencies: debug: 4.4.3 pretty-bytes: 6.1.1 tinyglobby: 0.2.15 - vite: 7.3.1(@types/node@24.12.0)(jiti@2.4.2)(lightningcss@1.31.1)(sass-embedded@1.97.3)(sass@1.97.3)(terser@5.31.6)(yaml@2.5.0) + vite: 7.3.1(@types/node@24.12.0)(jiti@2.4.2)(lightningcss@1.31.1)(sass-embedded@1.98.0)(sass@1.98.0)(terser@5.31.6)(yaml@2.5.0) workbox-build: 7.4.0 workbox-window: 7.4.0 transitivePeerDependencies: - supports-color - vite-plugin-vue-devtools@8.0.7(vite@7.3.1(@types/node@24.12.0)(jiti@2.4.2)(lightningcss@1.31.1)(sass-embedded@1.97.3)(sass@1.97.3)(terser@5.31.6)(yaml@2.5.0))(vue@3.5.27(typescript@5.9.3)): + vite-plugin-vue-devtools@8.0.7(vite@7.3.1(@types/node@24.12.0)(jiti@2.4.2)(lightningcss@1.31.1)(sass-embedded@1.98.0)(sass@1.98.0)(terser@5.31.6)(yaml@2.5.0))(vue@3.5.27(typescript@5.9.3)): dependencies: '@vue/devtools-core': 8.0.7(vue@3.5.27(typescript@5.9.3)) '@vue/devtools-kit': 8.0.7 '@vue/devtools-shared': 8.0.7 sirv: 3.0.2 - vite: 7.3.1(@types/node@24.12.0)(jiti@2.4.2)(lightningcss@1.31.1)(sass-embedded@1.97.3)(sass@1.97.3)(terser@5.31.6)(yaml@2.5.0) - vite-plugin-inspect: 11.3.3(vite@7.3.1(@types/node@24.12.0)(jiti@2.4.2)(lightningcss@1.31.1)(sass-embedded@1.97.3)(sass@1.97.3)(terser@5.31.6)(yaml@2.5.0)) - vite-plugin-vue-inspector: 5.3.2(vite@7.3.1(@types/node@24.12.0)(jiti@2.4.2)(lightningcss@1.31.1)(sass-embedded@1.97.3)(sass@1.97.3)(terser@5.31.6)(yaml@2.5.0)) + vite: 7.3.1(@types/node@24.12.0)(jiti@2.4.2)(lightningcss@1.31.1)(sass-embedded@1.98.0)(sass@1.98.0)(terser@5.31.6)(yaml@2.5.0) + vite-plugin-inspect: 11.3.3(vite@7.3.1(@types/node@24.12.0)(jiti@2.4.2)(lightningcss@1.31.1)(sass-embedded@1.98.0)(sass@1.98.0)(terser@5.31.6)(yaml@2.5.0)) + vite-plugin-vue-inspector: 5.3.2(vite@7.3.1(@types/node@24.12.0)(jiti@2.4.2)(lightningcss@1.31.1)(sass-embedded@1.98.0)(sass@1.98.0)(terser@5.31.6)(yaml@2.5.0)) transitivePeerDependencies: - '@nuxt/kit' - supports-color - vue - vite-plugin-vue-inspector@5.3.2(vite@7.3.1(@types/node@24.12.0)(jiti@2.4.2)(lightningcss@1.31.1)(sass-embedded@1.97.3)(sass@1.97.3)(terser@5.31.6)(yaml@2.5.0)): + vite-plugin-vue-inspector@5.3.2(vite@7.3.1(@types/node@24.12.0)(jiti@2.4.2)(lightningcss@1.31.1)(sass-embedded@1.98.0)(sass@1.98.0)(terser@5.31.6)(yaml@2.5.0)): dependencies: '@babel/core': 7.26.0 '@babel/plugin-proposal-decorators': 7.25.9(@babel/core@7.26.0) @@ -13514,7 +13514,7 @@ snapshots: '@vue/compiler-dom': 3.5.27 kolorist: 1.8.0 magic-string: 0.30.21 - vite: 7.3.1(@types/node@24.12.0)(jiti@2.4.2)(lightningcss@1.31.1)(sass-embedded@1.97.3)(sass@1.97.3)(terser@5.31.6)(yaml@2.5.0) + vite: 7.3.1(@types/node@24.12.0)(jiti@2.4.2)(lightningcss@1.31.1)(sass-embedded@1.98.0)(sass@1.98.0)(terser@5.31.6)(yaml@2.5.0) transitivePeerDependencies: - supports-color @@ -13526,7 +13526,7 @@ snapshots: transitivePeerDependencies: - supports-color - vite@7.3.1(@types/node@24.12.0)(jiti@2.4.2)(lightningcss@1.31.1)(sass-embedded@1.97.3)(sass@1.97.3)(terser@5.31.6)(yaml@2.5.0): + vite@7.3.1(@types/node@24.12.0)(jiti@2.4.2)(lightningcss@1.31.1)(sass-embedded@1.98.0)(sass@1.98.0)(terser@5.31.6)(yaml@2.5.0): dependencies: esbuild: 0.27.3 fdir: 6.5.0(picomatch@4.0.3) @@ -13539,15 +13539,15 @@ snapshots: fsevents: 2.3.3 jiti: 2.4.2 lightningcss: 1.31.1 - sass: 1.97.3 - sass-embedded: 1.97.3 + sass: 1.98.0 + sass-embedded: 1.98.0 terser: 5.31.6 yaml: 2.5.0 - vitest@4.0.18(@types/node@24.12.0)(happy-dom@20.8.3)(jiti@2.4.2)(jsdom@27.4.0)(lightningcss@1.31.1)(sass-embedded@1.97.3)(sass@1.97.3)(terser@5.31.6)(yaml@2.5.0): + vitest@4.0.18(@types/node@24.12.0)(happy-dom@20.8.3)(jiti@2.4.2)(jsdom@27.4.0)(lightningcss@1.31.1)(sass-embedded@1.98.0)(sass@1.98.0)(terser@5.31.6)(yaml@2.5.0): dependencies: '@vitest/expect': 4.0.18 - '@vitest/mocker': 4.0.18(vite@7.3.1(@types/node@24.12.0)(jiti@2.4.2)(lightningcss@1.31.1)(sass-embedded@1.97.3)(sass@1.97.3)(terser@5.31.6)(yaml@2.5.0)) + '@vitest/mocker': 4.0.18(vite@7.3.1(@types/node@24.12.0)(jiti@2.4.2)(lightningcss@1.31.1)(sass-embedded@1.98.0)(sass@1.98.0)(terser@5.31.6)(yaml@2.5.0)) '@vitest/pretty-format': 4.0.18 '@vitest/runner': 4.0.18 '@vitest/snapshot': 4.0.18 @@ -13564,7 +13564,7 @@ snapshots: tinyexec: 1.0.2 tinyglobby: 0.2.15 tinyrainbow: 3.0.3 - vite: 7.3.1(@types/node@24.12.0)(jiti@2.4.2)(lightningcss@1.31.1)(sass-embedded@1.97.3)(sass@1.97.3)(terser@5.31.6)(yaml@2.5.0) + vite: 7.3.1(@types/node@24.12.0)(jiti@2.4.2)(lightningcss@1.31.1)(sass-embedded@1.98.0)(sass@1.98.0)(terser@5.31.6)(yaml@2.5.0) why-is-node-running: 2.3.0 optionalDependencies: '@types/node': 24.12.0 From 28cc9e0571c98bb04d216e5fe47aaa503a1e887b Mon Sep 17 00:00:00 2001 From: Tink Date: Wed, 11 Mar 2026 09:37:46 +0100 Subject: [PATCH 058/142] fix: prevent authenticated UI flash when server rejects JWT session (#2387) --- frontend/src/stores/auth.ts | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/frontend/src/stores/auth.ts b/frontend/src/stores/auth.ts index b471a729a..aec224245 100644 --- a/frontend/src/stores/auth.ts +++ b/frontend/src/stores/auth.ts @@ -337,7 +337,14 @@ export const useAuthStore = defineStore('auth', () => { } if (isAuthenticated) { - await refreshUserInfo() + const user = await refreshUserInfo() + if (!user) { + // refreshUserInfo() did not return a user — either the + // token vanished or a 4xx triggered logout(). Bail out + // so the stale local `isAuthenticated` doesn't override + // the auth state that logout() already set. + return + } } } From ada2ebab9e1738bb145db1c498d2dda84d11c10b Mon Sep 17 00:00:00 2001 From: Tink Date: Wed, 11 Mar 2026 09:40:09 +0100 Subject: [PATCH 059/142] fix: preserve CalDAV inverse relations when parent has no RELATED-TO (#2389) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Fixes `removeStaleRelations` in CalDAV storage provider to only remove relations of kinds explicitly declared in the incoming VTODO's `RELATED-TO` properties - When a VTODO has no `RELATED-TO` at all (e.g., a parent task from Tasks.org), no relations are removed — they were auto-created as inverses by child tasks - When a VTODO declares specific relation kinds (e.g., `RELATED-TO;RELTYPE=PARENT`), only relations of that kind are checked for staleness; other kinds (like auto-created `subtask` inverses) are preserved Fixes #2383 --------- Co-authored-by: kolaente --- pkg/routes/caldav/listStorageProvider.go | 19 ++ pkg/webtests/caldav_test.go | 253 +++++++++++++++++++++++ 2 files changed, 272 insertions(+) diff --git a/pkg/routes/caldav/listStorageProvider.go b/pkg/routes/caldav/listStorageProvider.go index b9d97c92b..d73eb4fe0 100644 --- a/pkg/routes/caldav/listStorageProvider.go +++ b/pkg/routes/caldav/listStorageProvider.go @@ -523,6 +523,25 @@ func removeStaleRelations(s *xorm.Session, a web.Auth, task *models.Task, newRel for relationKind, relatedTasks := range existingTask.RelatedTasks { + // Only process CalDAV-compatible relation kinds (parenttask, subtask). + // Other kinds (related, blocking, etc.) are never set via CalDAV and + // should not be removed here. + if relationKind != models.RelationKindParenttask && relationKind != models.RelationKindSubtask { + continue + } + + // For subtask relations: only consider removal if the VTODO explicitly + // declares RELATED-TO;RELTYPE=CHILD (i.e., subtask kind is a key in + // newRelations). Subtask relations are often auto-created as inverses + // when child tasks declare RELATED-TO;RELTYPE=PARENT pointing to this + // task. Removing them just because this task's VTODO doesn't mention + // RELATED-TO;RELTYPE=CHILD would break those child-declared links. + if relationKind == models.RelationKindSubtask { + if _, hasSubtaskKind := newRelations[models.RelationKindSubtask]; !hasSubtaskKind { + continue + } + } + for _, relatedTask := range relatedTasks { relationInNewList := slices.ContainsFunc(newRelations[relationKind], func(newRelation *models.Task) bool { return newRelation.UID == relatedTask.UID }) diff --git a/pkg/webtests/caldav_test.go b/pkg/webtests/caldav_test.go index f57057823..98950e380 100644 --- a/pkg/webtests/caldav_test.go +++ b/pkg/webtests/caldav_test.go @@ -22,6 +22,8 @@ import ( "strings" "testing" + "code.vikunja.io/api/pkg/db" + "code.vikunja.io/api/pkg/models" "code.vikunja.io/api/pkg/routes/caldav" ics "github.com/arran4/golang-ical" @@ -212,6 +214,257 @@ END:VTODO` assert.Contains(t, rec.Body.String(), "RELATED-TO;RELTYPE=PARENT:uid_child_import") }) + t.Run("Import Task & Subtask (Reverse - Parent without RELATED-TO)", func(t *testing.T) { + e, _ := setupTestEnv() + + // Step 1: Subtask arrives FIRST, referencing a parent that doesn't exist yet. + // This is the standard Tasks.org behavior: only the child has RELATED-TO. + const vtodoSubtaskStub = `BEGIN:VTODO +UID:uid_child_no_reltype +DTSTAMP:20230301T073337Z +SUMMARY:Subtask without parent RELTYPE +CREATED:20230301T073337Z +LAST-MODIFIED:20230301T073337Z +RELATED-TO;RELTYPE=PARENT:uid_parent_no_reltype +END:VTODO` + + const subtaskVTODO = vtodoHeader + vtodoSubtaskStub + vtodoFooter + rec, err := newCaldavTestRequestWithUser(t, e, http.MethodPut, caldav.TaskHandler, &testuser15, subtaskVTODO, nil, map[string]string{"project": "36", "task": "uid_child_no_reltype"}) + require.NoError(t, err) + assert.Equal(t, 201, rec.Result().StatusCode) + + // Step 2: Parent arrives with NO RELATED-TO at all. + // This is how Tasks.org sends parent tasks — no RELATED-TO;RELTYPE=CHILD. + const vtodoParentStub = `BEGIN:VTODO +UID:uid_parent_no_reltype +DTSTAMP:20230301T073337Z +SUMMARY:Parent without RELTYPE +CREATED:20230301T073337Z +LAST-MODIFIED:20230301T073337Z +END:VTODO` + + const parentVTODO = vtodoHeader + vtodoParentStub + vtodoFooter + rec, err = newCaldavTestRequestWithUser(t, e, http.MethodPut, caldav.TaskHandler, &testuser15, parentVTODO, nil, map[string]string{"project": "36", "task": "uid_parent_no_reltype"}) + require.NoError(t, err) + assert.Equal(t, 201, rec.Result().StatusCode) + + // Step 3: Verify relations at the DB level. + s := db.NewSession() + defer s.Close() + + childTasks, err := models.GetTasksByUIDs(s, []string{"uid_child_no_reltype"}, &testuser15) + require.NoError(t, err) + require.Len(t, childTasks, 1) + childTask := childTasks[0] + + parentTasks, err := models.GetTasksByUIDs(s, []string{"uid_parent_no_reltype"}, &testuser15) + require.NoError(t, err) + require.Len(t, parentTasks, 1) + parentTask := parentTasks[0] + + // Parent should have correct title (DUMMY should have been replaced) + assert.Equal(t, "Parent without RELTYPE", parentTask.Title) + + // No DUMMY-UID tasks should remain + db.AssertMissing(t, "tasks", map[string]interface{}{ + "title": "DUMMY-UID-uid_parent_no_reltype", + }) + + // Subtask should still have parenttask relation to parent + db.AssertExists(t, "task_relations", map[string]interface{}{ + "task_id": childTask.ID, + "other_task_id": parentTask.ID, + "relation_kind": models.RelationKindParenttask, + }, false) + + // Parent should have the inverse subtask relation + db.AssertExists(t, "task_relations", map[string]interface{}{ + "task_id": parentTask.ID, + "other_task_id": childTask.ID, + "relation_kind": models.RelationKindSubtask, + }, false) + }) + + t.Run("Parent re-sync without RELATED-TO preserves child relations", func(t *testing.T) { + e, _ := setupTestEnv() + + // Step 1: Parent created first (no RELATED-TO). + const vtodoParentStub = `BEGIN:VTODO +UID:uid_parent_resync +DTSTAMP:20230301T073337Z +SUMMARY:Parent for resync test +CREATED:20230301T073337Z +LAST-MODIFIED:20230301T073337Z +END:VTODO` + + const parentVTODO = vtodoHeader + vtodoParentStub + vtodoFooter + rec, err := newCaldavTestRequestWithUser(t, e, http.MethodPut, caldav.TaskHandler, &testuser15, parentVTODO, nil, map[string]string{"project": "36", "task": "uid_parent_resync"}) + require.NoError(t, err) + assert.Equal(t, 201, rec.Result().StatusCode) + + // Step 2: Subtask arrives with RELATED-TO;RELTYPE=PARENT. + const vtodoSubtaskStub = `BEGIN:VTODO +UID:uid_child_resync +DTSTAMP:20230301T073337Z +SUMMARY:Child for resync test +CREATED:20230301T073337Z +LAST-MODIFIED:20230301T073337Z +RELATED-TO;RELTYPE=PARENT:uid_parent_resync +END:VTODO` + + const subtaskVTODO = vtodoHeader + vtodoSubtaskStub + vtodoFooter + rec, err = newCaldavTestRequestWithUser(t, e, http.MethodPut, caldav.TaskHandler, &testuser15, subtaskVTODO, nil, map[string]string{"project": "36", "task": "uid_child_resync"}) + require.NoError(t, err) + assert.Equal(t, 201, rec.Result().StatusCode) + + // Step 3: Parent is re-synced (updated) — still no RELATED-TO. + // This simulates DAVx5 re-syncing the parent after a change (e.g., title update). + const vtodoParentUpdatedStub = `BEGIN:VTODO +UID:uid_parent_resync +DTSTAMP:20230302T073337Z +SUMMARY:Parent for resync test (updated) +CREATED:20230301T073337Z +LAST-MODIFIED:20230302T073337Z +END:VTODO` + + const parentUpdatedVTODO = vtodoHeader + vtodoParentUpdatedStub + vtodoFooter + rec, err = newCaldavTestRequestWithUser(t, e, http.MethodPut, caldav.TaskHandler, &testuser15, parentUpdatedVTODO, nil, map[string]string{"project": "36", "task": "uid_parent_resync"}) + require.NoError(t, err) + assert.Equal(t, 201, rec.Result().StatusCode) + + // Step 4: Verify relations still intact after parent re-sync. + s := db.NewSession() + defer s.Close() + + parentTasks, err := models.GetTasksByUIDs(s, []string{"uid_parent_resync"}, &testuser15) + require.NoError(t, err) + require.Len(t, parentTasks, 1) + parentTask := parentTasks[0] + + childTasks, err := models.GetTasksByUIDs(s, []string{"uid_child_resync"}, &testuser15) + require.NoError(t, err) + require.Len(t, childTasks, 1) + childTask := childTasks[0] + + // Parent should have updated title + assert.Equal(t, "Parent for resync test (updated)", parentTask.Title) + + // Child should still have parenttask relation to parent + db.AssertExists(t, "task_relations", map[string]interface{}{ + "task_id": childTask.ID, + "other_task_id": parentTask.ID, + "relation_kind": models.RelationKindParenttask, + }, false) + + // Parent should still have inverse subtask relation + db.AssertExists(t, "task_relations", map[string]interface{}{ + "task_id": parentTask.ID, + "other_task_id": childTask.ID, + "relation_kind": models.RelationKindSubtask, + }, false) + }) + + t.Run("Multiple subtasks with same parent (one-sided RELATED-TO)", func(t *testing.T) { + e, _ := setupTestEnv() + + // Step 1: First subtask arrives, parent doesn't exist yet. + const vtodoSubtask1Stub = `BEGIN:VTODO +UID:uid_multi_child_1 +DTSTAMP:20230301T073337Z +SUMMARY:Multi child 1 +CREATED:20230301T073337Z +LAST-MODIFIED:20230301T073337Z +RELATED-TO;RELTYPE=PARENT:uid_multi_parent +END:VTODO` + + const subtask1VTODO = vtodoHeader + vtodoSubtask1Stub + vtodoFooter + rec, err := newCaldavTestRequestWithUser(t, e, http.MethodPut, caldav.TaskHandler, &testuser15, subtask1VTODO, nil, map[string]string{"project": "36", "task": "uid_multi_child_1"}) + require.NoError(t, err) + assert.Equal(t, 201, rec.Result().StatusCode) + + // Step 2: Second subtask arrives, parent should exist as DUMMY now. + const vtodoSubtask2Stub = `BEGIN:VTODO +UID:uid_multi_child_2 +DTSTAMP:20230301T073337Z +SUMMARY:Multi child 2 +CREATED:20230301T073337Z +LAST-MODIFIED:20230301T073337Z +RELATED-TO;RELTYPE=PARENT:uid_multi_parent +END:VTODO` + + const subtask2VTODO = vtodoHeader + vtodoSubtask2Stub + vtodoFooter + rec, err = newCaldavTestRequestWithUser(t, e, http.MethodPut, caldav.TaskHandler, &testuser15, subtask2VTODO, nil, map[string]string{"project": "36", "task": "uid_multi_child_2"}) + require.NoError(t, err) + assert.Equal(t, 201, rec.Result().StatusCode) + + // Step 3: Parent arrives with NO RELATED-TO. + const vtodoParentStub = `BEGIN:VTODO +UID:uid_multi_parent +DTSTAMP:20230301T073337Z +SUMMARY:Multi parent +CREATED:20230301T073337Z +LAST-MODIFIED:20230301T073337Z +END:VTODO` + + const parentVTODO = vtodoHeader + vtodoParentStub + vtodoFooter + rec, err = newCaldavTestRequestWithUser(t, e, http.MethodPut, caldav.TaskHandler, &testuser15, parentVTODO, nil, map[string]string{"project": "36", "task": "uid_multi_parent"}) + require.NoError(t, err) + assert.Equal(t, 201, rec.Result().StatusCode) + + // Step 4: Verify all relations intact and no DUMMY tasks. + s := db.NewSession() + defer s.Close() + + parentTasks, err := models.GetTasksByUIDs(s, []string{"uid_multi_parent"}, &testuser15) + require.NoError(t, err) + require.Len(t, parentTasks, 1) + parentTask := parentTasks[0] + + child1Tasks, err := models.GetTasksByUIDs(s, []string{"uid_multi_child_1"}, &testuser15) + require.NoError(t, err) + require.Len(t, child1Tasks, 1) + child1Task := child1Tasks[0] + + child2Tasks, err := models.GetTasksByUIDs(s, []string{"uid_multi_child_2"}, &testuser15) + require.NoError(t, err) + require.Len(t, child2Tasks, 1) + child2Task := child2Tasks[0] + + // Parent should have correct title + assert.Equal(t, "Multi parent", parentTask.Title) + + // No DUMMY-UID tasks should remain + db.AssertMissing(t, "tasks", map[string]interface{}{ + "title": "DUMMY-UID-uid_multi_parent", + }) + + // Child 1 should have parenttask relation to parent + db.AssertExists(t, "task_relations", map[string]interface{}{ + "task_id": child1Task.ID, + "other_task_id": parentTask.ID, + "relation_kind": models.RelationKindParenttask, + }, false) + + // Child 2 should have parenttask relation to parent + db.AssertExists(t, "task_relations", map[string]interface{}{ + "task_id": child2Task.ID, + "other_task_id": parentTask.ID, + "relation_kind": models.RelationKindParenttask, + }, false) + + // Parent should have inverse subtask relations to both children + db.AssertExists(t, "task_relations", map[string]interface{}{ + "task_id": parentTask.ID, + "other_task_id": child1Task.ID, + "relation_kind": models.RelationKindSubtask, + }, false) + db.AssertExists(t, "task_relations", map[string]interface{}{ + "task_id": parentTask.ID, + "other_task_id": child2Task.ID, + "relation_kind": models.RelationKindSubtask, + }, false) + }) + t.Run("Delete Subtask", func(t *testing.T) { e, _ := setupTestEnv() From 9bcdbb64335b364b8ae16ed951992527a6cd7002 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Sat, 14 Mar 2026 22:49:09 +0000 Subject: [PATCH 060/142] chore(deps): update dev-dependencies (#2395) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This PR contains the following updates: | Package | Change | [Age](https://docs.renovatebot.com/merge-confidence/) | [Confidence](https://docs.renovatebot.com/merge-confidence/) | |---|---|---|---| | [@vitejs/plugin-vue](https://redirect.github.com/vitejs/vite-plugin-vue/tree/main/packages/plugin-vue#readme) ([source](https://redirect.github.com/vitejs/vite-plugin-vue/tree/HEAD/packages/plugin-vue)) | [`6.0.4` → `6.0.5`](https://renovatebot.com/diffs/npm/@vitejs%2fplugin-vue/6.0.4/6.0.5) | ![age](https://developer.mend.io/api/mc/badges/age/npm/@vitejs%2fplugin-vue/6.0.5?slim=true) | ![confidence](https://developer.mend.io/api/mc/badges/confidence/npm/@vitejs%2fplugin-vue/6.0.4/6.0.5?slim=true) | | [caniuse-lite](https://redirect.github.com/browserslist/caniuse-lite) | [`1.0.30001777` → `1.0.30001778`](https://renovatebot.com/diffs/npm/caniuse-lite/1.0.30001777/1.0.30001778) | ![age](https://developer.mend.io/api/mc/badges/age/npm/caniuse-lite/1.0.30001778?slim=true) | ![confidence](https://developer.mend.io/api/mc/badges/confidence/npm/caniuse-lite/1.0.30001777/1.0.30001778?slim=true) | | [electron](https://redirect.github.com/electron/electron) | [`40.8.0` → `40.8.2`](https://renovatebot.com/diffs/npm/electron/40.8.0/40.8.2) | ![age](https://developer.mend.io/api/mc/badges/age/npm/electron/40.8.2?slim=true) | ![confidence](https://developer.mend.io/api/mc/badges/confidence/npm/electron/40.8.0/40.8.2?slim=true) | | [esbuild](https://redirect.github.com/evanw/esbuild) | [`0.27.3` → `0.27.4`](https://renovatebot.com/diffs/npm/esbuild/0.27.3/0.27.4) | ![age](https://developer.mend.io/api/mc/badges/age/npm/esbuild/0.27.4?slim=true) | ![confidence](https://developer.mend.io/api/mc/badges/confidence/npm/esbuild/0.27.3/0.27.4?slim=true) | | [happy-dom](https://redirect.github.com/capricorn86/happy-dom) | [`20.8.3` → `20.8.4`](https://renovatebot.com/diffs/npm/happy-dom/20.8.3/20.8.4) | ![age](https://developer.mend.io/api/mc/badges/age/npm/happy-dom/20.8.4?slim=true) | ![confidence](https://developer.mend.io/api/mc/badges/confidence/npm/happy-dom/20.8.3/20.8.4?slim=true) | | [vite-plugin-vue-devtools](https://redirect.github.com/vuejs/devtools) ([source](https://redirect.github.com/vuejs/devtools/tree/HEAD/packages/vite)) | [`8.0.7` → `8.1.0`](https://renovatebot.com/diffs/npm/vite-plugin-vue-devtools/8.0.7/8.1.0) | ![age](https://developer.mend.io/api/mc/badges/age/npm/vite-plugin-vue-devtools/8.1.0?slim=true) | ![confidence](https://developer.mend.io/api/mc/badges/confidence/npm/vite-plugin-vue-devtools/8.0.7/8.1.0?slim=true) | | [vitest](https://vitest.dev) ([source](https://redirect.github.com/vitest-dev/vitest/tree/HEAD/packages/vitest)) | [`4.0.18` → `4.1.0`](https://renovatebot.com/diffs/npm/vitest/4.0.18/4.1.0) | ![age](https://developer.mend.io/api/mc/badges/age/npm/vitest/4.1.0?slim=true) | ![confidence](https://developer.mend.io/api/mc/badges/confidence/npm/vitest/4.0.18/4.1.0?slim=true) | --- ### Release Notes
vitejs/vite-plugin-vue (@​vitejs/plugin-vue) ### [`v6.0.5`](https://redirect.github.com/vitejs/vite-plugin-vue/blob/HEAD/packages/plugin-vue/CHANGELOG.md#small-605-2026-03-12-small) ##### Miscellaneous Chores - remove Vite 8 beta from supported range ([#​746](https://redirect.github.com/vitejs/vite-plugin-vue/issues/746)) ([b3f23e4](https://redirect.github.com/vitejs/vite-plugin-vue/commit/b3f23e4d0818f11a3e2f674380da870b11d260a2))
browserslist/caniuse-lite (caniuse-lite) ### [`v1.0.30001778`](https://redirect.github.com/browserslist/caniuse-lite/compare/1.0.30001777...1.0.30001778) [Compare Source](https://redirect.github.com/browserslist/caniuse-lite/compare/1.0.30001777...1.0.30001778)
electron/electron (electron) ### [`v40.8.2`](https://redirect.github.com/electron/electron/releases/tag/v40.8.2): electron v40.8.2 [Compare Source](https://redirect.github.com/electron/electron/compare/v40.8.1...v40.8.2) ### Release Notes for v40.8.2 #### Other Changes - Backported fix for b/491421267. [#​50229](https://redirect.github.com/electron/electron/pull/50229) - Fixed an issue where running app icons were not correctly retrieved on macOS Tahoe. [#​50188](https://redirect.github.com/electron/electron/pull/50188) ### [`v40.8.1`](https://redirect.github.com/electron/electron/releases/tag/v40.8.1): electron v40.8.1 [Compare Source](https://redirect.github.com/electron/electron/compare/v40.8.0...v40.8.1) ### Release Notes for v40.8.1 #### Fixes - Added validation to protocol client methods to reject protocol names that do not conform to the RFC 3986 URI scheme grammar. [#​50158](https://redirect.github.com/electron/electron/pull/50158) (Also in [38](https://redirect.github.com/electron/electron/pull/50157), [39](https://redirect.github.com/electron/electron/pull/50156), [41](https://redirect.github.com/electron/electron/pull/50155)) - Fixed an issue on macOS where calling `autoUpdater.quitAndInstall()` could fail if `checkForUpdates()` was called again after an update was already downloaded. [#​50216](https://redirect.github.com/electron/electron/pull/50216) (Also in [39](https://redirect.github.com/electron/electron/pull/50215), [41](https://redirect.github.com/electron/electron/pull/50217)) - Fixed an issue where Chrome Devtools menus may not appear in certain embedded windows. [#​50138](https://redirect.github.com/electron/electron/pull/50138) (Also in [39](https://redirect.github.com/electron/electron/pull/50136), [41](https://redirect.github.com/electron/electron/pull/50137)) - Fixed an issue where `additionalData` passed to `app.requestSingleInstanceLock` on Windows could be truncated or fail to deserialize in the primary instance's `second-instance` event. [#​50162](https://redirect.github.com/electron/electron/pull/50162) (Also in [38](https://redirect.github.com/electron/electron/pull/50177), [39](https://redirect.github.com/electron/electron/pull/50174), [41](https://redirect.github.com/electron/electron/pull/50154)) - Fixed an issue where `screen.getCursorScreenPoint()` crashed on Wayland when it was called before a `BrowserWindow` had been created. [#​50104](https://redirect.github.com/electron/electron/pull/50104) (Also in [39](https://redirect.github.com/electron/electron/pull/50106), [41](https://redirect.github.com/electron/electron/pull/50105)) - Fixed an issue where calling `setBounds` on a `WebContentsView` could trigger redundant `page-favicon-updated` events even when the favicon had not changed. [#​50084](https://redirect.github.com/electron/electron/pull/50084) (Also in [39](https://redirect.github.com/electron/electron/pull/50086), [41](https://redirect.github.com/electron/electron/pull/50085)) - Fixed an issue where invalid characters in custom protocol or webRequest response header values were not rejected. [#​50131](https://redirect.github.com/electron/electron/pull/50131) (Also in [38](https://redirect.github.com/electron/electron/pull/50130), [39](https://redirect.github.com/electron/electron/pull/50129), [41](https://redirect.github.com/electron/electron/pull/50132)) - Fixed an issue where permission and device-chooser handlers received the top-level page origin instead of the requesting subframe's origin. [#​50149](https://redirect.github.com/electron/electron/pull/50149) (Also in [38](https://redirect.github.com/electron/electron/pull/50151), [39](https://redirect.github.com/electron/electron/pull/50147), [41](https://redirect.github.com/electron/electron/pull/50148)) - Fixed an issue where traffic light buttons would flash at position (0,0) when restoring a window with a custom `trafficLightPosition` from minimization on macOS. [#​50207](https://redirect.github.com/electron/electron/pull/50207) (Also in [39](https://redirect.github.com/electron/electron/pull/50208), [41](https://redirect.github.com/electron/electron/pull/50209)) - Fixed bug where opening a message box immediately upon closing a child window may cause the parent window to freeze on Windows. [#​50189](https://redirect.github.com/electron/electron/pull/50189) (Also in [39](https://redirect.github.com/electron/electron/pull/50190), [41](https://redirect.github.com/electron/electron/pull/50191)) - Reverted AltGr key fix that caused menu bar to no longer show on Windows. [#​50110](https://redirect.github.com/electron/electron/pull/50110) (Also in [39](https://redirect.github.com/electron/electron/pull/50109), [41](https://redirect.github.com/electron/electron/pull/50111)) #### Other Changes - Backported fix for chromium:485622239. [#​50168](https://redirect.github.com/electron/electron/pull/50168)
evanw/esbuild (esbuild) ### [`v0.27.4`](https://redirect.github.com/evanw/esbuild/blob/HEAD/CHANGELOG.md#0274) [Compare Source](https://redirect.github.com/evanw/esbuild/compare/v0.27.3...v0.27.4) - Fix a regression with CSS media queries ([#​4395](https://redirect.github.com/evanw/esbuild/issues/4395), [#​4405](https://redirect.github.com/evanw/esbuild/issues/4405), [#​4406](https://redirect.github.com/evanw/esbuild/issues/4406)) Version 0.25.11 of esbuild introduced support for parsing media queries. This unintentionally introduced a regression with printing media queries that use the ` and ` grammar. Specifically, esbuild was failing to wrap an `or` clause with parentheses when inside ``. This release fixes the regression. Here is an example: ```css /* Original code */ @​media only screen and ((min-width: 10px) or (min-height: 10px)) { a { color: red } } /* Old output (incorrect) */ @​media only screen and (min-width: 10px) or (min-height: 10px) { a { color: red; } } /* New output (correct) */ @​media only screen and ((min-width: 10px) or (min-height: 10px)) { a { color: red; } } ``` - Fix an edge case with the `inject` feature ([#​4407](https://redirect.github.com/evanw/esbuild/issues/4407)) This release fixes an edge case where esbuild's `inject` feature could not be used with arbitrary module namespace names exported using an `export {} from` statement with bundling disabled and a target environment where arbitrary module namespace names is unsupported. With the fix, the following `inject` file: ```js import jquery from 'jquery'; export { jquery as 'window.jQuery' }; ``` Can now always be rewritten as this without esbuild sometimes incorrectly generating an error: ```js export { default as 'window.jQuery' } from 'jquery'; ``` - Attempt to improve API handling of huge metafiles ([#​4329](https://redirect.github.com/evanw/esbuild/issues/4329), [#​4415](https://redirect.github.com/evanw/esbuild/issues/4415)) This release contains a few changes that attempt to improve the behavior of esbuild's JavaScript API with huge metafiles (esbuild's name for the build metadata, formatted as a JSON object). The JavaScript API is designed to return the metafile JSON as a JavaScript object in memory, which makes it easy to access from within a JavaScript-based plugin. Multiple people have encountered issues where this API breaks down with a pathologically-large metafile. The primary issue is that V8 has an implementation-specific maximum string length, so using the `JSON.parse` API with large enough strings is impossible. This release will now attempt to use a fallback JavaScript-based JSON parser that operates directly on the UTF8-encoded JSON bytes instead of using `JSON.parse` when the JSON metafile is too big to fit in a JavaScript string. The new fallback path has not yet been heavily-tested. The metafile will also now be generated with whitespace removed if the bundle is significantly large, which will reduce the size of the metafile JSON slightly. However, hitting this case is potentially a sign that something else is wrong. Ideally you wouldn't be building something so enormous that the build metadata can't even fit inside a JavaScript string. You may want to consider optimizing your project, or breaking up your project into multiple parts that are built independently. Another option could potentially be to use esbuild's command-line API instead of its JavaScript API, which is more efficient (although of course then you can't use JavaScript plugins, so it may not be an option).
capricorn86/happy-dom (happy-dom) ### [`v20.8.4`](https://redirect.github.com/capricorn86/happy-dom/compare/v20.8.3...82a0888cb2c87a6123e05424b528f8e8c9b3e426) [Compare Source](https://redirect.github.com/capricorn86/happy-dom/compare/v20.8.3...v20.8.4)
vuejs/devtools (vite-plugin-vue-devtools) ### [`v8.1.0`](https://redirect.github.com/vuejs/devtools/releases/tag/v8.1.0) [Compare Source](https://redirect.github.com/vuejs/devtools/compare/v8.0.7...v8.1.0) *No significant changes* #####     [View changes on GitHub](https://redirect.github.com/vuejs/devtools/compare/v8.0.8...v8.1.0)
vitest-dev/vitest (vitest) ### [`v4.1.0`](https://redirect.github.com/vitest-dev/vitest/releases/tag/v4.1.0) [Compare Source](https://redirect.github.com/vitest-dev/vitest/compare/v4.0.18...v4.1.0) Vitest 4.1 is out! This release page lists all changes made to the project during the 4.1 beta. To get a review of all the new features, read our [blog post](https://vitest.dev/blog/vitest-4). #####    🚀 Features - Return a disposable from doMock()  -  by [@​kirkwaiblinger](https://redirect.github.com/kirkwaiblinger) in [#​9332](https://redirect.github.com/vitest-dev/vitest/issues/9332) [(e3e65)](https://redirect.github.com/vitest-dev/vitest/commit/e3e659a96) - Added chai style assertions  -  by [@​ronnakamoto](https://redirect.github.com/ronnakamoto) and [@​sheremet-va](https://redirect.github.com/sheremet-va) in [#​8842](https://redirect.github.com/vitest-dev/vitest/issues/8842) [(841df)](https://redirect.github.com/vitest-dev/vitest/commit/841df9ac5) - Update to sinon/fake-timers v15 and add `setTickMode` to timer controls  -  by [@​atscott](https://redirect.github.com/atscott) and [@​sheremet-va](https://redirect.github.com/sheremet-va) in [#​8726](https://redirect.github.com/vitest-dev/vitest/issues/8726) [(4b480)](https://redirect.github.com/vitest-dev/vitest/commit/4b480aaed) - Expose matcher types  -  by [@​sheremet-va](https://redirect.github.com/sheremet-va) in [#​9448](https://redirect.github.com/vitest-dev/vitest/issues/9448) [(3e4b9)](https://redirect.github.com/vitest-dev/vitest/commit/3e4b913b1) - Add `toTestSpecification` to reported tasks  -  by [@​sheremet-va](https://redirect.github.com/sheremet-va) in [#​9464](https://redirect.github.com/vitest-dev/vitest/issues/9464) [(1a470)](https://redirect.github.com/vitest-dev/vitest/commit/1a4705da9) - Show a warning if `vi.mock` or `vi.hoisted` are declared outside of top level of the module  -  by [@​sheremet-va](https://redirect.github.com/sheremet-va) in [#​9387](https://redirect.github.com/vitest-dev/vitest/issues/9387) [(5db54)](https://redirect.github.com/vitest-dev/vitest/commit/5db54a468) - Track and display expectedly failed tests (.fails) in UI and CLI  -  by [@​Copilot](https://redirect.github.com/Copilot), **sheremet-va** and [@​sheremet-va](https://redirect.github.com/sheremet-va) in [#​9476](https://redirect.github.com/vitest-dev/vitest/issues/9476) [(77d75)](https://redirect.github.com/vitest-dev/vitest/commit/77d75fd34) - Support tags  -  by [@​sheremet-va](https://redirect.github.com/sheremet-va) in [#​9478](https://redirect.github.com/vitest-dev/vitest/issues/9478) [(de7c8)](https://redirect.github.com/vitest-dev/vitest/commit/de7c8a521) - Implement `aroundEach` and `aroundAll` hooks  -  by [@​sheremet-va](https://redirect.github.com/sheremet-va) in [#​9450](https://redirect.github.com/vitest-dev/vitest/issues/9450) [(2a8cb)](https://redirect.github.com/vitest-dev/vitest/commit/2a8cb9dc2) - Stabilize experimental features  -  by [@​sheremet-va](https://redirect.github.com/sheremet-va) in [#​9529](https://redirect.github.com/vitest-dev/vitest/issues/9529) [(b5fd2)](https://redirect.github.com/vitest-dev/vitest/commit/b5fd2a16a) - Accept `new` or `all` in `--update` flag  -  by [@​sheremet-va](https://redirect.github.com/sheremet-va) in [#​9543](https://redirect.github.com/vitest-dev/vitest/issues/9543) [(a5acf)](https://redirect.github.com/vitest-dev/vitest/commit/a5acf28a5) - Support `meta` in test options  -  by [@​sheremet-va](https://redirect.github.com/sheremet-va) in [#​9535](https://redirect.github.com/vitest-dev/vitest/issues/9535) [(7d622)](https://redirect.github.com/vitest-dev/vitest/commit/7d622e3d1) - Support type inference with a new `test.extend` syntax  -  by [@​sheremet-va](https://redirect.github.com/sheremet-va) in [#​9550](https://redirect.github.com/vitest-dev/vitest/issues/9550) [(e5385)](https://redirect.github.com/vitest-dev/vitest/commit/e53854fcc) - Support vite 8 beta, fix type issues in the config with different vite versions  -  by [@​sheremet-va](https://redirect.github.com/sheremet-va) in [#​9587](https://redirect.github.com/vitest-dev/vitest/issues/9587) [(99028)](https://redirect.github.com/vitest-dev/vitest/commit/990281dfd) - Add assertion helper to hide internal stack traces  -  by [@​hi-ogawa](https://redirect.github.com/hi-ogawa) and **Claude Opus 4.6** in [#​9594](https://redirect.github.com/vitest-dev/vitest/issues/9594) [(eeb0a)](https://redirect.github.com/vitest-dev/vitest/commit/eeb0ae2f8) - Store failure screenshots using artifacts API  -  by [@​macarie](https://redirect.github.com/macarie) in [#​9588](https://redirect.github.com/vitest-dev/vitest/issues/9588) [(24603)](https://redirect.github.com/vitest-dev/vitest/commit/24603e3c4) - Allow `vitest list` to statically collect tests instead of running files to collect them  -  by [@​sheremet-va](https://redirect.github.com/sheremet-va) in [#​9630](https://redirect.github.com/vitest-dev/vitest/issues/9630) [(7a8e7)](https://redirect.github.com/vitest-dev/vitest/commit/7a8e7fc20) - Add `--detect-async-leaks`  -  by [@​AriPerkkio](https://redirect.github.com/AriPerkkio) in [#​9528](https://redirect.github.com/vitest-dev/vitest/issues/9528) [(c594d)](https://redirect.github.com/vitest-dev/vitest/commit/c594d4af3) - Implement `mockThrow` and `mockThrowOnce`  -  by [@​thor-juhasz](https://redirect.github.com/thor-juhasz) and [@​sheremet-va](https://redirect.github.com/sheremet-va) in [#​9512](https://redirect.github.com/vitest-dev/vitest/issues/9512) [(61917)](https://redirect.github.com/vitest-dev/vitest/commit/619179fb7) - Support `update: "none"` and add docs about snapshots behavior on CI  -  by [@​hi-ogawa](https://redirect.github.com/hi-ogawa) in [#​9700](https://redirect.github.com/vitest-dev/vitest/issues/9700) [(05f18)](https://redirect.github.com/vitest-dev/vitest/commit/05f1854e2) - Support playwright `launchOptions` with `connectOptions`  -  by [@​hi-ogawa](https://redirect.github.com/hi-ogawa) in [#​9702](https://redirect.github.com/vitest-dev/vitest/issues/9702) [(f0ff1)](https://redirect.github.com/vitest-dev/vitest/commit/f0ff1b2a0) - Add `page/locator.mark` API to enhance playwright trace  -  by [@​hi-ogawa](https://redirect.github.com/hi-ogawa) in [#​9652](https://redirect.github.com/vitest-dev/vitest/issues/9652) [(d0ee5)](https://redirect.github.com/vitest-dev/vitest/commit/d0ee546fe) - **api**: - Support tests starting or ending with `test` in `experimental_parseSpecification`  -  by [@​jgillick](https://redirect.github.com/jgillick) and **Jeremy Gillick** in [#​9235](https://redirect.github.com/vitest-dev/vitest/issues/9235) [(2f367)](https://redirect.github.com/vitest-dev/vitest/commit/2f367fad3) - Add filters to `createSpecification`  -  by [@​sheremet-va](https://redirect.github.com/sheremet-va) in [#​9336](https://redirect.github.com/vitest-dev/vitest/issues/9336) [(c8e6c)](https://redirect.github.com/vitest-dev/vitest/commit/c8e6c7fbf) - Expose `runTestFiles` as alternative to `runTestSpecifications`  -  by [@​sheremet-va](https://redirect.github.com/sheremet-va) in [#​9443](https://redirect.github.com/vitest-dev/vitest/issues/9443) [(43d76)](https://redirect.github.com/vitest-dev/vitest/commit/43d761821) - Add `allowWrite` and `allowExec` options to `api`  -  by [@​sheremet-va](https://redirect.github.com/sheremet-va) in [#​9350](https://redirect.github.com/vitest-dev/vitest/issues/9350) [(20e00)](https://redirect.github.com/vitest-dev/vitest/commit/20e00ef78) - Allow passing down test cases to `toTestSpecification`  -  by [@​sheremet-va](https://redirect.github.com/sheremet-va) in [#​9627](https://redirect.github.com/vitest-dev/vitest/issues/9627) [(6f17d)](https://redirect.github.com/vitest-dev/vitest/commit/6f17d5ddf) - **browser**: - Add `userEvent.wheel` API  -  by [@​macarie](https://redirect.github.com/macarie) in [#​9188](https://redirect.github.com/vitest-dev/vitest/issues/9188) [(66080)](https://redirect.github.com/vitest-dev/vitest/commit/660801979) - Add `filterNode` option to prettyDOM for filtering browser assertion error output  -  by [@​Copilot](https://redirect.github.com/Copilot), **sheremet-va** and [@​sheremet-va](https://redirect.github.com/sheremet-va) in [#​9475](https://redirect.github.com/vitest-dev/vitest/issues/9475) [(d3220)](https://redirect.github.com/vitest-dev/vitest/commit/d3220fcd8) - Support playwright persistent context  -  by [@​hi-ogawa](https://redirect.github.com/hi-ogawa), **Claude Opus 4.6** and [@​sheremet-va](https://redirect.github.com/sheremet-va) in [#​9229](https://redirect.github.com/vitest-dev/vitest/issues/9229) [(f865d)](https://redirect.github.com/vitest-dev/vitest/commit/f865d2ba4) - Added `detailsPanelPosition` option and button  -  by [@​shairez](https://redirect.github.com/shairez) in [#​9525](https://redirect.github.com/vitest-dev/vitest/issues/9525) [(c8a31)](https://redirect.github.com/vitest-dev/vitest/commit/c8a31147c) - Use BlazeDiff instead of pixelmatch  -  by [@​macarie](https://redirect.github.com/macarie) in [#​9514](https://redirect.github.com/vitest-dev/vitest/issues/9514) [(30936)](https://redirect.github.com/vitest-dev/vitest/commit/309362089) - Add `findElement` and enable strict mode in webdriverio and preview  -  by [@​sheremet-va](https://redirect.github.com/sheremet-va) in [#​9677](https://redirect.github.com/vitest-dev/vitest/issues/9677) [(c3f37)](https://redirect.github.com/vitest-dev/vitest/commit/c3f37721c) - **cli**: - Add [@​bomb](https://redirect.github.com/bomb).sh/tab completions  -  by [@​AmirSa12](https://redirect.github.com/AmirSa12) and [@​sheremet-va](https://redirect.github.com/sheremet-va) in [#​8639](https://redirect.github.com/vitest-dev/vitest/issues/8639) [(200f3)](https://redirect.github.com/vitest-dev/vitest/commit/200f31704) - **coverage**: - Support `ignore start/stop` ignore hints  -  by [@​AriPerkkio](https://redirect.github.com/AriPerkkio) in [#​9204](https://redirect.github.com/vitest-dev/vitest/issues/9204) [(e59c9)](https://redirect.github.com/vitest-dev/vitest/commit/e59c94ba6) - Add `coverage.changed` option to report only changed files  -  by [@​kykim00](https://redirect.github.com/kykim00) and [@​AriPerkkio](https://redirect.github.com/AriPerkkio) in [#​9521](https://redirect.github.com/vitest-dev/vitest/issues/9521) [(1d939)](https://redirect.github.com/vitest-dev/vitest/commit/1d9392c67) - **experimental**: - Add `onModuleRunner` hook to `worker.init`  -  by [@​sheremet-va](https://redirect.github.com/sheremet-va) in [#​9286](https://redirect.github.com/vitest-dev/vitest/issues/9286) [(e977f)](https://redirect.github.com/vitest-dev/vitest/commit/e977f3deb) - Option to disable the module runner  -  by [@​sheremet-va](https://redirect.github.com/sheremet-va) and [@​AriPerkkio](https://redirect.github.com/AriPerkkio) in [#​9210](https://redirect.github.com/vitest-dev/vitest/issues/9210) [(9be61)](https://redirect.github.com/vitest-dev/vitest/commit/9be6121ee) - Add `importDurations: { limit, print }` options  -  by [@​hi-ogawa](https://redirect.github.com/hi-ogawa), **Claude Opus 4.6** and [@​sheremet-va](https://redirect.github.com/sheremet-va) in [#​9401](https://redirect.github.com/vitest-dev/vitest/issues/9401) [(7e10f)](https://redirect.github.com/vitest-dev/vitest/commit/7e10fb356) - Add print and fail thresholds for `importDurations`  -  by [@​hi-ogawa](https://redirect.github.com/hi-ogawa) and **Claude Opus 4.6** in [#​9533](https://redirect.github.com/vitest-dev/vitest/issues/9533) [(3f7a5)](https://redirect.github.com/vitest-dev/vitest/commit/3f7a5f8f8) - **fixtures**: - Pass down file context to `beforeAll`/`afterAll`  -  by [@​sheremet-va](https://redirect.github.com/sheremet-va) in [#​9572](https://redirect.github.com/vitest-dev/vitest/issues/9572) [(c8339)](https://redirect.github.com/vitest-dev/vitest/commit/c83395f2c) - **reporters**: - Add `agent` reporter to reduce ai agent token usage  -  by [@​cpojer](https://redirect.github.com/cpojer) in [#​9779](https://redirect.github.com/vitest-dev/vitest/issues/9779) [(3e9e0)](https://redirect.github.com/vitest-dev/vitest/commit/3e9e096a2) - **runner**: - Enhance `retry` options  -  by [@​MazenSamehR](https://redirect.github.com/MazenSamehR), **Matan Shavit**, [@​AriPerkkio](https://redirect.github.com/AriPerkkio) and [@​sheremet-va](https://redirect.github.com/sheremet-va) in [#​9370](https://redirect.github.com/vitest-dev/vitest/issues/9370) [(9e4cf)](https://redirect.github.com/vitest-dev/vitest/commit/9e4cfd295) - **ui**: - Allow run individual test/suites  -  by [@​userquin](https://redirect.github.com/userquin) in [#​9465](https://redirect.github.com/vitest-dev/vitest/issues/9465) [(73b10)](https://redirect.github.com/vitest-dev/vitest/commit/73b10f1b9) - Add project filter/sort support  -  by [@​userquin](https://redirect.github.com/userquin) in [#​8689](https://redirect.github.com/vitest-dev/vitest/issues/8689) [(0c7ea)](https://redirect.github.com/vitest-dev/vitest/commit/0c7eaac16) - Add duration sorting to explorer  -  by [@​julianhahn](https://redirect.github.com/julianhahn) and [@​cursoragent](https://redirect.github.com/cursoragent) in [#​9603](https://redirect.github.com/vitest-dev/vitest/issues/9603) [(209b1)](https://redirect.github.com/vitest-dev/vitest/commit/209b1b0e1) - Implement filter for slow tests  -  by [@​DerYeger](https://redirect.github.com/DerYeger) and [@​userquin](https://redirect.github.com/userquin) in [#​9705](https://redirect.github.com/vitest-dev/vitest/issues/9705) [(8880c)](https://redirect.github.com/vitest-dev/vitest/commit/8880c907a) - **vitest**: - Add run summary in GitHub Actions Reporter  -  by [@​macarie](https://redirect.github.com/macarie) and **jhnance** in [#​9579](https://redirect.github.com/vitest-dev/vitest/issues/9579) [(96bfc)](https://redirect.github.com/vitest-dev/vitest/commit/96bfc8345) #####    🐞 Bug Fixes - Deprecate several vitest/\* entry points  -  by [@​sheremet-va](https://redirect.github.com/sheremet-va) in [#​9347](https://redirect.github.com/vitest-dev/vitest/issues/9347) [(fd459)](https://redirect.github.com/vitest-dev/vitest/commit/fd45928be) - Use `meta.url` in `createRequire`  -  by [@​sheremet-va](https://redirect.github.com/sheremet-va) in [#​9441](https://redirect.github.com/vitest-dev/vitest/issues/9441) [(e3422)](https://redirect.github.com/vitest-dev/vitest/commit/e34225563) - Preact browser mode init example of render function not async  -  by [@​WuMingDao](https://redirect.github.com/WuMingDao) in [#​9375](https://redirect.github.com/vitest-dev/vitest/issues/9375) [(2bea5)](https://redirect.github.com/vitest-dev/vitest/commit/2bea549c7) - Deprecate unused types in matcher context  -  by [@​sheremet-va](https://redirect.github.com/sheremet-va) in [#​9449](https://redirect.github.com/vitest-dev/vitest/issues/9449) [(20f87)](https://redirect.github.com/vitest-dev/vitest/commit/20f8753a2) - Handle `external/noExternal` during `configEnvironment` hook  -  by [@​hi-ogawa](https://redirect.github.com/hi-ogawa) and **Claude Opus 4.6** in [#​9508](https://redirect.github.com/vitest-dev/vitest/issues/9508) [(59ea2)](https://redirect.github.com/vitest-dev/vitest/commit/59ea27c1c) - Replace default ssr environment runner with Vitest server module runner  -  by [@​hi-ogawa](https://redirect.github.com/hi-ogawa) and **Claude Opus 4.6** in [#​9506](https://redirect.github.com/vitest-dev/vitest/issues/9506) [(cd5db)](https://redirect.github.com/vitest-dev/vitest/commit/cd5db660c) - Propagate experimental CLI options to child projects  -  by [@​hi-ogawa](https://redirect.github.com/hi-ogawa) and **Claude Opus 4.6** in [#​9531](https://redirect.github.com/vitest-dev/vitest/issues/9531) [(b624f)](https://redirect.github.com/vitest-dev/vitest/commit/b624fae53) - Show a warning when `browser.isolate` is used  -  by [@​sheremet-va](https://redirect.github.com/sheremet-va) in [#​9410](https://redirect.github.com/vitest-dev/vitest/issues/9410) [(3d48e)](https://redirect.github.com/vitest-dev/vitest/commit/3d48ebcb9) - Fix `vi.mock({ spy: true })` node v8 coverage  -  by [@​hi-ogawa](https://redirect.github.com/hi-ogawa), **hi-ogawa** and **Claude Opus 4.6** in [#​9541](https://redirect.github.com/vitest-dev/vitest/issues/9541) [(687b6)](https://redirect.github.com/vitest-dev/vitest/commit/687b633c1) - Don't show internal ssr handler in errors  -  by [@​sheremet-va](https://redirect.github.com/sheremet-va) in [#​9547](https://redirect.github.com/vitest-dev/vitest/issues/9547) [(76c43)](https://redirect.github.com/vitest-dev/vitest/commit/76c4397b5) - Close vitest if it failed to start  -  by [@​sheremet-va](https://redirect.github.com/sheremet-va) in [#​9573](https://redirect.github.com/vitest-dev/vitest/issues/9573) [(728ba)](https://redirect.github.com/vitest-dev/vitest/commit/728ba617f) - Fix ssr environment runner in project  -  by [@​hi-ogawa](https://redirect.github.com/hi-ogawa) in [#​9584](https://redirect.github.com/vitest-dev/vitest/issues/9584) [(09006)](https://redirect.github.com/vitest-dev/vitest/commit/090064f97) - Trim trailing white spaces in code block  -  by [@​hi-ogawa](https://redirect.github.com/hi-ogawa) in [#​9591](https://redirect.github.com/vitest-dev/vitest/issues/9591) [(f78be)](https://redirect.github.com/vitest-dev/vitest/commit/f78bea992) - Support inline snapshot inside test.for/each  -  by [@​hi-ogawa](https://redirect.github.com/hi-ogawa) in [#​9590](https://redirect.github.com/vitest-dev/vitest/issues/9590) [(615fd)](https://redirect.github.com/vitest-dev/vitest/commit/615fd521e) - Apply source maps for external module stack trace  -  by [@​hi-ogawa](https://redirect.github.com/hi-ogawa) in [#​9152](https://redirect.github.com/vitest-dev/vitest/issues/9152) [(79e20)](https://redirect.github.com/vitest-dev/vitest/commit/79e20d5a3) - Remove the `.name` from statically collected test  -  by [@​sheremet-va](https://redirect.github.com/sheremet-va) in [#​9596](https://redirect.github.com/vitest-dev/vitest/issues/9596) [(b66ff)](https://redirect.github.com/vitest-dev/vitest/commit/b66ff691a) - Don't suppress warnings on pnp  -  by [@​sheremet-va](https://redirect.github.com/sheremet-va) in [#​9602](https://redirect.github.com/vitest-dev/vitest/issues/9602) [(89cbd)](https://redirect.github.com/vitest-dev/vitest/commit/89cbdaea3) - Support snapshot with `expect.soft`  -  by [@​iumehara](https://redirect.github.com/iumehara), [@​hi-ogawa](https://redirect.github.com/hi-ogawa) and **Claude Opus 4.6** in [#​9231](https://redirect.github.com/vitest-dev/vitest/issues/9231) [(3eb2c)](https://redirect.github.com/vitest-dev/vitest/commit/3eb2cd541) - Log seed when only `sequence.shuffle.tests` is enabled  -  by [@​kaigritun](https://redirect.github.com/kaigritun), **Kai Gritun** and [@​sheremet-va](https://redirect.github.com/sheremet-va) in [#​9576](https://redirect.github.com/vitest-dev/vitest/issues/9576) [(8182b)](https://redirect.github.com/vitest-dev/vitest/commit/8182b77ad) - Externalize `expect/src/utils` from `vitest`  -  by [@​hi-ogawa](https://redirect.github.com/hi-ogawa) in [#​9616](https://redirect.github.com/vitest-dev/vitest/issues/9616) [(48739)](https://redirect.github.com/vitest-dev/vitest/commit/487398422) - Ignore test.override during static collection  -  by [@​sheremet-va](https://redirect.github.com/sheremet-va) in [#​9620](https://redirect.github.com/vitest-dev/vitest/issues/9620) [(09174)](https://redirect.github.com/vitest-dev/vitest/commit/0917470ce) - Increase stacktrace limit for `--detect-async-leaks`  -  by [@​AriPerkkio](https://redirect.github.com/AriPerkkio) in [#​9638](https://redirect.github.com/vitest-dev/vitest/issues/9638) [(9fd4c)](https://redirect.github.com/vitest-dev/vitest/commit/9fd4ce533) - Hanging-reporter link in cli  -  by [@​flx-sta](https://redirect.github.com/flx-sta) in [#​9649](https://redirect.github.com/vitest-dev/vitest/issues/9649) [(7c103)](https://redirect.github.com/vitest-dev/vitest/commit/7c103055c) - Fix teardown timeout of `aroundEach/All` when inner `aroundEach/All` throws  -  by [@​hi-ogawa](https://redirect.github.com/hi-ogawa) in [#​9657](https://redirect.github.com/vitest-dev/vitest/issues/9657) [(4ec6c)](https://redirect.github.com/vitest-dev/vitest/commit/4ec6cb305) - Fix ui mode / html reporter and coverage integration  -  by [@​hi-ogawa](https://redirect.github.com/hi-ogawa) and **Claude Opus 4.6** in [#​9626](https://redirect.github.com/vitest-dev/vitest/issues/9626) [(86fad)](https://redirect.github.com/vitest-dev/vitest/commit/86fad4b42) - Don't continue when `aroundEach/All` setup timed out  -  by [@​hi-ogawa](https://redirect.github.com/hi-ogawa) in [#​9670](https://redirect.github.com/vitest-dev/vitest/issues/9670) [(bb013)](https://redirect.github.com/vitest-dev/vitest/commit/bb013d54b) - Align `VitestRunnerConfig` optional fields with `SerializedConfig`  -  by [@​hi-ogawa](https://redirect.github.com/hi-ogawa) in [#​9661](https://redirect.github.com/vitest-dev/vitest/issues/9661) [(79520)](https://redirect.github.com/vitest-dev/vitest/commit/79520d82d) - Handle Symbol values in format utility  -  by [@​nami8824](https://redirect.github.com/nami8824) in [#​9658](https://redirect.github.com/vitest-dev/vitest/issues/9658) [(0583f)](https://redirect.github.com/vitest-dev/vitest/commit/0583f067e) - Deprecate `toBe*` spy assertions in favor of `toHaveBeen*` (and `toThrowError`)  -  by [@​sheremet-va](https://redirect.github.com/sheremet-va) in [#​9665](https://redirect.github.com/vitest-dev/vitest/issues/9665) [(4d390)](https://redirect.github.com/vitest-dev/vitest/commit/4d390dfe9) - Don't propagate nested `aroundEach/All` errors but aggregate them on runner  -  by [@​hi-ogawa](https://redirect.github.com/hi-ogawa) in [#​9673](https://redirect.github.com/vitest-dev/vitest/issues/9673) [(b6365)](https://redirect.github.com/vitest-dev/vitest/commit/b63653f5a) - Show a better error if there is a pending dynamic import  -  by [@​sheremet-va](https://redirect.github.com/sheremet-va) in [#​9676](https://redirect.github.com/vitest-dev/vitest/issues/9676) [(7ef5c)](https://redirect.github.com/vitest-dev/vitest/commit/7ef5cf4b7) - Preserve stack trace of `resolves/rejects` chained assertion error  -  by [@​hi-ogawa](https://redirect.github.com/hi-ogawa) in [#​9679](https://redirect.github.com/vitest-dev/vitest/issues/9679) [(c6151)](https://redirect.github.com/vitest-dev/vitest/commit/c61511d4a) - Handle module-sync condition in vmThreads/vmForks require  -  by [@​lesleh](https://redirect.github.com/lesleh) in [#​9650](https://redirect.github.com/vitest-dev/vitest/issues/9650) and [#​9651](https://redirect.github.com/vitest-dev/vitest/issues/9651) [(bb203)](https://redirect.github.com/vitest-dev/vitest/commit/bb20389f4) - Hooks should respect `maxConcurrency`  -  by [@​hi-ogawa](https://redirect.github.com/hi-ogawa) in [#​9653](https://redirect.github.com/vitest-dev/vitest/issues/9653) [(16d13)](https://redirect.github.com/vitest-dev/vitest/commit/16d13d981) - Recursively autospy module object  -  by [@​hi-ogawa](https://redirect.github.com/hi-ogawa) in [#​9687](https://redirect.github.com/vitest-dev/vitest/issues/9687) [(695a8)](https://redirect.github.com/vitest-dev/vitest/commit/695a86b41) - Remove trailing spaces from diff error log  -  by [@​hi-ogawa](https://redirect.github.com/hi-ogawa) and [@​sheremet-va](https://redirect.github.com/sheremet-va) in [#​9680](https://redirect.github.com/vitest-dev/vitest/issues/9680) [(395d1)](https://redirect.github.com/vitest-dev/vitest/commit/395d1a29e) - Respect project `resolve.conditions` for externals  -  by [@​hi-ogawa](https://redirect.github.com/hi-ogawa) in [#​9717](https://redirect.github.com/vitest-dev/vitest/issues/9717) [(1d498)](https://redirect.github.com/vitest-dev/vitest/commit/1d4987498) - Use object for WeakMap instead of a symbol to support webcontainers  -  by [@​sheremet-va](https://redirect.github.com/sheremet-va) in [#​9731](https://redirect.github.com/vitest-dev/vitest/issues/9731) [(c5225)](https://redirect.github.com/vitest-dev/vitest/commit/c52259330) - Fix re-mocking virtual module  -  by [@​hi-ogawa](https://redirect.github.com/hi-ogawa) in [#​9748](https://redirect.github.com/vitest-dev/vitest/issues/9748) [(3cbbb)](https://redirect.github.com/vitest-dev/vitest/commit/3cbbb17f1) - Cancelling should stop current test immediately  -  by [@​AriPerkkio](https://redirect.github.com/AriPerkkio) in [#​9729](https://redirect.github.com/vitest-dev/vitest/issues/9729) [(0cb2f)](https://redirect.github.com/vitest-dev/vitest/commit/0cb2f7239) - Make `mockObject` change backwards compatible  -  by [@​sheremet-va](https://redirect.github.com/sheremet-va) in [#​9744](https://redirect.github.com/vitest-dev/vitest/issues/9744) [(84c69)](https://redirect.github.com/vitest-dev/vitest/commit/84c69497f) - Fix `URL.name` on jsdom  -  by [@​hi-ogawa](https://redirect.github.com/hi-ogawa) in [#​9767](https://redirect.github.com/vitest-dev/vitest/issues/9767) [(031f3)](https://redirect.github.com/vitest-dev/vitest/commit/031f3a374) - Save and restore module graph in blob reporter  -  by [@​hi-ogawa](https://redirect.github.com/hi-ogawa) in [#​9740](https://redirect.github.com/vitest-dev/vitest/issues/9740) [(84355)](https://redirect.github.com/vitest-dev/vitest/commit/843554bf0) - Don't silence reporter errors from test runtime events handler in normal run and --merge-reports  -  by [@​hi-ogawa](https://redirect.github.com/hi-ogawa) in [#​9727](https://redirect.github.com/vitest-dev/vitest/issues/9727) [(4072d)](https://redirect.github.com/vitest-dev/vitest/commit/4072d0132) - Fix `vi.importActual()` for virtual modules  -  by [@​hi-ogawa](https://redirect.github.com/hi-ogawa) and **Claude Opus 4.6** in [#​9772](https://redirect.github.com/vitest-dev/vitest/issues/9772) [(1e89e)](https://redirect.github.com/vitest-dev/vitest/commit/1e89ec020) - Throw `FixtureAccessError` if suite hook accesses undefined fixture  -  by [@​sheremet-va](https://redirect.github.com/sheremet-va) in [#​9786](https://redirect.github.com/vitest-dev/vitest/issues/9786) [(fc2ce)](https://redirect.github.com/vitest-dev/vitest/commit/fc2cea2b7) - Allow hyphens in project config file name pattern  -  by [@​Koutaro-Hanabusa](https://redirect.github.com/Koutaro-Hanabusa) and [@​hi-ogawa](https://redirect.github.com/hi-ogawa) in [#​9760](https://redirect.github.com/vitest-dev/vitest/issues/9760) [(33e96)](https://redirect.github.com/vitest-dev/vitest/commit/33e96311a) - Manual and redirect mock shouldn't `load` or `transform` original module  -  by [@​hi-ogawa](https://redirect.github.com/hi-ogawa) and **Claude Opus 4.6** in [#​9774](https://redirect.github.com/vitest-dev/vitest/issues/9774) [(a8216)](https://redirect.github.com/vitest-dev/vitest/commit/a8216b001) - `hideSkippedTests` should not hide `test.todo`  -  by [@​oilater](https://redirect.github.com/oilater) in [#​9562](https://redirect.github.com/vitest-dev/vitest/issues/9562) and [#​9781](https://redirect.github.com/vitest-dev/vitest/issues/9781) [(8181e)](https://redirect.github.com/vitest-dev/vitest/commit/8181e06e7) - Allow catch/finally for async assertion  -  by [@​hi-ogawa](https://redirect.github.com/hi-ogawa) in [#​9827](https://redirect.github.com/vitest-dev/vitest/issues/9827) [(031f0)](https://redirect.github.com/vitest-dev/vitest/commit/031f02a89) - Resolve fixture overrides from test's suite in `beforeEach` hooks  -  by [@​hi-ogawa](https://redirect.github.com/hi-ogawa) and **Claude Opus 4.6** in [#​9826](https://redirect.github.com/vitest-dev/vitest/issues/9826) [(99e52)](https://redirect.github.com/vitest-dev/vitest/commit/99e52fe58) - Use isAgent check, not just TTY, for watch mode  -  by [@​sheremet-va](https://redirect.github.com/sheremet-va) in [#​9841](https://redirect.github.com/vitest-dev/vitest/issues/9841) [(c3cac)](https://redirect.github.com/vitest-dev/vitest/commit/c3cac1c1b) - Use `performance.now` to measure test timeout duration  -  by [@​hi-ogawa](https://redirect.github.com/hi-ogawa) and **Claude Opus 4.6** in [#​9795](https://redirect.github.com/vitest-dev/vitest/issues/9795) [(f48a6)](https://redirect.github.com/vitest-dev/vitest/commit/f48a60114) - Correctly identify concurrent test during static analysis  -  by [@​sheremet-va](https://redirect.github.com/sheremet-va) in [#​9846](https://redirect.github.com/vitest-dev/vitest/issues/9846) [(1de0a)](https://redirect.github.com/vitest-dev/vitest/commit/1de0aa22d) - **browser**: - Avoid updating screenshots when `toMatchScreenshot` passes  -  by [@​macarie](https://redirect.github.com/macarie) in [#​9289](https://redirect.github.com/vitest-dev/vitest/issues/9289) [(46aab)](https://redirect.github.com/vitest-dev/vitest/commit/46aabaa44) - Hide injected data-testid attributes  -  by [@​sheremet-va](https://redirect.github.com/sheremet-va) in [#​9503](https://redirect.github.com/vitest-dev/vitest/issues/9503) [(c8d2c)](https://redirect.github.com/vitest-dev/vitest/commit/c8d2c411c) - Throw an error if iframe was reloaded  -  by [@​sheremet-va](https://redirect.github.com/sheremet-va) in [#​9516](https://redirect.github.com/vitest-dev/vitest/issues/9516) [(73a81)](https://redirect.github.com/vitest-dev/vitest/commit/73a81f880) - Encode projectName in browser client URL  -  by [@​dkkim0122](https://redirect.github.com/dkkim0122) in [#​9523](https://redirect.github.com/vitest-dev/vitest/issues/9523) [(5b164)](https://redirect.github.com/vitest-dev/vitest/commit/5b16483c3) - Don't take failure screenshot if tests have artifacts created by `toMatchScreenshot`  -  by [@​macarie](https://redirect.github.com/macarie) in [#​9552](https://redirect.github.com/vitest-dev/vitest/issues/9552) [(83ca0)](https://redirect.github.com/vitest-dev/vitest/commit/83ca02547) - Remove `--remote-debugging-address` from chrome args  -  by [@​hi-ogawa](https://redirect.github.com/hi-ogawa) and [@​AriPerkkio](https://redirect.github.com/AriPerkkio) in [#​9712](https://redirect.github.com/vitest-dev/vitest/issues/9712) [(f09bb)](https://redirect.github.com/vitest-dev/vitest/commit/f09bb5c32) - Make sure userEvent actions support `ensureAwaited`  -  by [@​sheremet-va](https://redirect.github.com/sheremet-va) in [#​9732](https://redirect.github.com/vitest-dev/vitest/issues/9732) [(97685)](https://redirect.github.com/vitest-dev/vitest/commit/9768517b8) - Types of `getCDPSession` and `cdp()`  -  by [@​AriPerkkio](https://redirect.github.com/AriPerkkio) in [#​9716](https://redirect.github.com/vitest-dev/vitest/issues/9716) [(689a2)](https://redirect.github.com/vitest-dev/vitest/commit/689a22a1b) - Skip esbuild.legalComments when using rolldown-vite  -  by [@​Copilot](https://redirect.github.com/Copilot), **hi-ogawa** and [@​hi-ogawa](https://redirect.github.com/hi-ogawa) in [#​9803](https://redirect.github.com/vitest-dev/vitest/issues/9803) [(3505f)](https://redirect.github.com/vitest-dev/vitest/commit/3505fa5a3) - **chai**: - Don't allow `deepEqual` in the config because it's not serializable  -  by [@​sheremet-va](https://redirect.github.com/sheremet-va) in [#​9666](https://redirect.github.com/vitest-dev/vitest/issues/9666) [(9ee99)](https://redirect.github.com/vitest-dev/vitest/commit/9ee999d73) - **coverage**: - Infer transform mode for uncovered files  -  by [@​AriPerkkio](https://redirect.github.com/AriPerkkio) in [#​9435](https://redirect.github.com/vitest-dev/vitest/issues/9435) [(f3967)](https://redirect.github.com/vitest-dev/vitest/commit/f396792d6) - `thresholds.autoUpdate` to preserve ending whitespace  -  by [@​AriPerkkio](https://redirect.github.com/AriPerkkio) in [#​9436](https://redirect.github.com/vitest-dev/vitest/issues/9436) [(7e534)](https://redirect.github.com/vitest-dev/vitest/commit/7e534a0b6) - **deps**: - Update all non-major dependencies  -  by [@​hi-ogawa](https://redirect.github.com/hi-ogawa) in [#​9192](https://redirect.github.com/vitest-dev/vitest/issues/9192) [(90c30)](https://redirect.github.com/vitest-dev/vitest/commit/90c302f3b) - Update all non-major dependencies  -  in [#​9485](https://redirect.github.com/vitest-dev/vitest/issues/9485) [(c0118)](https://redirect.github.com/vitest-dev/vitest/commit/c01186022) - Update all non-major dependencies  -  in [#​9567](https://redirect.github.com/vitest-dev/vitest/issues/9567) [(13c9e)](https://redirect.github.com/vitest-dev/vitest/commit/13c9e022b) - **docs**: - Fix old `/config/#option` hash links causing hydration errors  -  by [@​hi-ogawa](https://redirect.github.com/hi-ogawa), **Claude Opus 4.6** and [@​sheremet-va](https://redirect.github.com/sheremet-va) in [#​9610](https://redirect.github.com/vitest-dev/vitest/issues/9610) [(a603c)](https://redirect.github.com/vitest-dev/vitest/commit/a603c3a30) - **expect**: - `toMatchObject(Map/Set)` should expect `Map/Set` on left hand side  -  by [@​hi-ogawa](https://redirect.github.com/hi-ogawa) and **Claude Opus 4.6** in [#​9532](https://redirect.github.com/vitest-dev/vitest/issues/9532) [(381da)](https://redirect.github.com/vitest-dev/vitest/commit/381da4a9d) - Fix objectContaining with proxy  -  by [@​hi-ogawa](https://redirect.github.com/hi-ogawa) and **Claude Opus 4.6** in [#​9554](https://redirect.github.com/vitest-dev/vitest/issues/9554) [(7ce34)](https://redirect.github.com/vitest-dev/vitest/commit/7ce3417b1) - Support arbitrary value equality for `toThrow` and make Error detection robust  -  by [@​hi-ogawa](https://redirect.github.com/hi-ogawa) and **Claude Opus 4.6** in [#​9570](https://redirect.github.com/vitest-dev/vitest/issues/9570) [(de215)](https://redirect.github.com/vitest-dev/vitest/commit/de215c19c) - **mock**: - Inject helpers after hashbang if present  -  by [@​sheremet-va](https://redirect.github.com/sheremet-va) in [#​9545](https://redirect.github.com/vitest-dev/vitest/issues/9545) [(65432)](https://redirect.github.com/vitest-dev/vitest/commit/65432a74b) - **mocker**: - Update vite's peer dependency range  -  by [@​sheremet-va](https://redirect.github.com/sheremet-va) in [#​9808](https://redirect.github.com/vitest-dev/vitest/issues/9808) [(36f9a)](https://redirect.github.com/vitest-dev/vitest/commit/36f9a81a2) - **reporter**: - `dot` reporter leaves pending tests  -  by [@​AriPerkkio](https://redirect.github.com/AriPerkkio) in [#​9684](https://redirect.github.com/vitest-dev/vitest/issues/9684) [(4d793)](https://redirect.github.com/vitest-dev/vitest/commit/4d7938a56) - **runner**: - Mark repeated tests as finished on last run  -  by [@​AriPerkkio](https://redirect.github.com/AriPerkkio) in [#​9707](https://redirect.github.com/vitest-dev/vitest/issues/9707) [(cc735)](https://redirect.github.com/vitest-dev/vitest/commit/cc735970a) - **spy**: - Support deep partial in vi.mocked  -  by [@​j2h30728](https://redirect.github.com/j2h30728) in [#​8152](https://redirect.github.com/vitest-dev/vitest/issues/8152) and [#​9493](https://redirect.github.com/vitest-dev/vitest/issues/9493) [(71cb5)](https://redirect.github.com/vitest-dev/vitest/commit/71cb51ffc) - Fallback to object accessor if descriptor's value is `undefined`  -  by [@​sheremet-va](https://redirect.github.com/sheremet-va) in [#​9511](https://redirect.github.com/vitest-dev/vitest/issues/9511) [(6f181)](https://redirect.github.com/vitest-dev/vitest/commit/6f18103fa) - Throw correct errors when shorthand methods are used on a class  -  by [@​sheremet-va](https://redirect.github.com/sheremet-va) in [#​9513](https://redirect.github.com/vitest-dev/vitest/issues/9513) [(5d0fd)](https://redirect.github.com/vitest-dev/vitest/commit/5d0fd3b62) - **types**: - `bench.reporters` no longer gives type errors when passing file name string paths  -  by [@​Bertie690](https://redirect.github.com/Bertie690) in [#​9695](https://redirect.github.com/vitest-dev/vitest/issues/9695) [(093c8)](https://redirect.github.com/vitest-dev/vitest/commit/093c8f6b5) - **ui**: - Process artifact attachments when generating HTML reporter  -  by [@​macarie](https://redirect.github.com/macarie) in [#​9472](https://redirect.github.com/vitest-dev/vitest/issues/9472) [(96eb9)](https://redirect.github.com/vitest-dev/vitest/commit/96eb92826) - Don't fail if --ui and --root are specified together  -  by [@​sheremet-va](https://redirect.github.com/sheremet-va) in [#​9536](https://redirect.github.com/vitest-dev/vitest/issues/9536) [(d9305)](https://redirect.github.com/vitest-dev/vitest/commit/d93055fc7) #####    🏎 Performance - **pretty-format**: Combine DOMElement plugins  -  by [@​sheremet-va](https://redirect.github.com/sheremet-va) in [#​9581](https://redirect.github.com/vitest-dev/vitest/issues/9581) [(da85a)](https://redirect.github.com/vitest-dev/vitest/commit/da85a3267) #####     [View changes on GitHub](https://redirect.github.com/vitest-dev/vitest/compare/v4.0.17...v4.1.0)
--- ### Configuration 📅 **Schedule**: Branch creation - Between 12:00 AM and 03:59 AM ( * 0-3 * * * ) (UTC), Automerge - At any time (no schedule defined). 🚦 **Automerge**: Disabled by config. Please merge this manually once you are satisfied. ♻ **Rebasing**: Whenever PR becomes conflicted, or you tick the rebase/retry checkbox. 👻 **Immortal**: This PR will be recreated if closed unmerged. Get [config help](https://redirect.github.com/renovatebot/renovate/discussions) if that's undesired. --- - [ ] If you want to rebase/retry this PR, check this box --- This PR was generated by [Mend Renovate](https://mend.io/renovate/). View the [repository job log](https://developer.mend.io/github/go-vikunja/vikunja). Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- desktop/package.json | 2 +- desktop/pnpm-lock.yaml | 10 +- frontend/package.json | 12 +- frontend/pnpm-lock.yaml | 423 ++++++++++++++++++++-------------------- 4 files changed, 225 insertions(+), 222 deletions(-) diff --git a/desktop/package.json b/desktop/package.json index 7d30e11ec..7c7533f36 100644 --- a/desktop/package.json +++ b/desktop/package.json @@ -52,7 +52,7 @@ } }, "devDependencies": { - "electron": "40.8.0", + "electron": "40.8.2", "electron-builder": "26.8.1", "unzipper": "0.12.3" }, diff --git a/desktop/pnpm-lock.yaml b/desktop/pnpm-lock.yaml index a6c18b6af..03f53144c 100644 --- a/desktop/pnpm-lock.yaml +++ b/desktop/pnpm-lock.yaml @@ -18,8 +18,8 @@ importers: version: 5.2.1 devDependencies: electron: - specifier: 40.8.0 - version: 40.8.0 + specifier: 40.8.2 + version: 40.8.2 electron-builder: specifier: 26.8.1 version: 26.8.1(electron-builder-squirrel-windows@24.13.3) @@ -552,8 +552,8 @@ packages: electron-publish@26.8.1: resolution: {integrity: sha512-q+jrSTIh/Cv4eGZa7oVR+grEJo/FoLMYBAnSL5GCtqwUpr1T+VgKB/dn1pnzxIxqD8S/jP1yilT9VrwCqINR4w==} - electron@40.8.0: - resolution: {integrity: sha512-WoPq0Nr9Yx3g7T6VnJXdwa/rr2+VRyH3a+K+ezfMKBlf6WjxE/LmhMQabKbb6yjm9RbZhJBRcYyoLph421O2mQ==} + electron@40.8.2: + resolution: {integrity: sha512-EFgQHG0GBO9glpY/x2v4e7xH5uGuoKOQyXeleljlXZeThbjFsNu0NTUyTCVBOkoKT0F5xCwAOAHcI83b3b8jzA==} engines: {node: '>= 12.20.55'} hasBin: true @@ -2335,7 +2335,7 @@ snapshots: transitivePeerDependencies: - supports-color - electron@40.8.0: + electron@40.8.2: dependencies: '@electron/get': 2.0.3 '@types/node': 24.10.9 diff --git a/frontend/package.json b/frontend/package.json index 00fc35f36..632a56e6c 100644 --- a/frontend/package.json +++ b/frontend/package.json @@ -118,20 +118,20 @@ "@types/sortablejs": "1.15.9", "@typescript-eslint/eslint-plugin": "8.57.0", "@typescript-eslint/parser": "8.57.0", - "@vitejs/plugin-vue": "6.0.4", + "@vitejs/plugin-vue": "6.0.5", "@vue/eslint-config-typescript": "14.7.0", "@vue/test-utils": "2.4.6", "@vue/tsconfig": "0.9.0", "@vueuse/shared": "14.2.1", "autoprefixer": "10.4.27", "browserslist": "4.28.1", - "caniuse-lite": "1.0.30001777", + "caniuse-lite": "1.0.30001778", "csstype": "3.2.3", - "esbuild": "0.27.3", + "esbuild": "0.27.4", "eslint": "9.39.4", "eslint-plugin-depend": "1.5.0", "eslint-plugin-vue": "10.8.0", - "happy-dom": "20.8.3", + "happy-dom": "20.8.4", "histoire": "1.0.0-beta.1", "postcss": "8.5.8", "postcss-easing-gradients": "3.0.1", @@ -149,9 +149,9 @@ "unplugin-inject-preload": "3.0.0", "vite": "7.3.1", "vite-plugin-pwa": "1.2.0", - "vite-plugin-vue-devtools": "8.0.7", + "vite-plugin-vue-devtools": "8.1.0", "vite-svg-loader": "5.1.1", - "vitest": "4.0.18", + "vitest": "4.1.0", "vue-tsc": "3.2.5", "wait-on": "9.0.4", "workbox-cli": "7.4.0" diff --git a/frontend/pnpm-lock.yaml b/frontend/pnpm-lock.yaml index 34a8f79c8..3339f98c3 100644 --- a/frontend/pnpm-lock.yaml +++ b/frontend/pnpm-lock.yaml @@ -211,8 +211,8 @@ importers: specifier: 8.57.0 version: 8.57.0(eslint@9.39.4(jiti@2.4.2))(typescript@5.9.3) '@vitejs/plugin-vue': - specifier: 6.0.4 - version: 6.0.4(vite@7.3.1(@types/node@24.12.0)(jiti@2.4.2)(lightningcss@1.31.1)(sass-embedded@1.98.0)(sass@1.98.0)(terser@5.31.6)(yaml@2.5.0))(vue@3.5.27(typescript@5.9.3)) + specifier: 6.0.5 + version: 6.0.5(vite@7.3.1(@types/node@24.12.0)(jiti@2.4.2)(lightningcss@1.31.1)(sass-embedded@1.98.0)(sass@1.98.0)(terser@5.31.6)(yaml@2.5.0))(vue@3.5.27(typescript@5.9.3)) '@vue/eslint-config-typescript': specifier: 14.7.0 version: 14.7.0(eslint-plugin-vue@10.8.0(@typescript-eslint/parser@8.57.0(eslint@9.39.4(jiti@2.4.2))(typescript@5.9.3))(eslint@9.39.4(jiti@2.4.2))(vue-eslint-parser@10.4.0(eslint@9.39.4(jiti@2.4.2))))(eslint@9.39.4(jiti@2.4.2))(typescript@5.9.3) @@ -232,14 +232,14 @@ importers: specifier: 4.28.1 version: 4.28.1 caniuse-lite: - specifier: 1.0.30001777 - version: 1.0.30001777 + specifier: 1.0.30001778 + version: 1.0.30001778 csstype: specifier: 3.2.3 version: 3.2.3 esbuild: - specifier: 0.27.3 - version: 0.27.3 + specifier: 0.27.4 + version: 0.27.4 eslint: specifier: 9.39.4 version: 9.39.4(jiti@2.4.2) @@ -250,8 +250,8 @@ importers: specifier: 10.8.0 version: 10.8.0(@typescript-eslint/parser@8.57.0(eslint@9.39.4(jiti@2.4.2))(typescript@5.9.3))(eslint@9.39.4(jiti@2.4.2))(vue-eslint-parser@10.4.0(eslint@9.39.4(jiti@2.4.2))) happy-dom: - specifier: 20.8.3 - version: 20.8.3 + specifier: 20.8.4 + version: 20.8.4 histoire: specifier: 1.0.0-beta.1 version: 1.0.0-beta.1(@types/node@24.12.0)(lightningcss@1.31.1)(sass-embedded@1.98.0)(sass@1.98.0)(terser@5.31.6)(vite@7.3.1(@types/node@24.12.0)(jiti@2.4.2)(lightningcss@1.31.1)(sass-embedded@1.98.0)(sass@1.98.0)(terser@5.31.6)(yaml@2.5.0))(yaml@2.5.0) @@ -304,14 +304,14 @@ importers: specifier: 1.2.0 version: 1.2.0(vite@7.3.1(@types/node@24.12.0)(jiti@2.4.2)(lightningcss@1.31.1)(sass-embedded@1.98.0)(sass@1.98.0)(terser@5.31.6)(yaml@2.5.0))(workbox-build@7.4.0)(workbox-window@7.4.0) vite-plugin-vue-devtools: - specifier: 8.0.7 - version: 8.0.7(vite@7.3.1(@types/node@24.12.0)(jiti@2.4.2)(lightningcss@1.31.1)(sass-embedded@1.98.0)(sass@1.98.0)(terser@5.31.6)(yaml@2.5.0))(vue@3.5.27(typescript@5.9.3)) + specifier: 8.1.0 + version: 8.1.0(vite@7.3.1(@types/node@24.12.0)(jiti@2.4.2)(lightningcss@1.31.1)(sass-embedded@1.98.0)(sass@1.98.0)(terser@5.31.6)(yaml@2.5.0))(vue@3.5.27(typescript@5.9.3)) vite-svg-loader: specifier: 5.1.1 version: 5.1.1(vue@3.5.27(typescript@5.9.3)) vitest: - specifier: 4.0.18 - version: 4.0.18(@types/node@24.12.0)(happy-dom@20.8.3)(jiti@2.4.2)(jsdom@27.4.0)(lightningcss@1.31.1)(sass-embedded@1.98.0)(sass@1.98.0)(terser@5.31.6)(yaml@2.5.0) + specifier: 4.1.0 + version: 4.1.0(@types/node@24.12.0)(happy-dom@20.8.4)(jsdom@27.4.0)(vite@7.3.1(@types/node@24.12.0)(jiti@2.4.2)(lightningcss@1.31.1)(sass-embedded@1.98.0)(sass@1.98.0)(terser@5.31.6)(yaml@2.5.0)) vue-tsc: specifier: 3.2.5 version: 3.2.5(typescript@5.9.3) @@ -1260,8 +1260,8 @@ packages: cpu: [ppc64] os: [aix] - '@esbuild/aix-ppc64@0.27.3': - resolution: {integrity: sha512-9fJMTNFTWZMh5qwrBItuziu834eOCUcEqymSH7pY+zoMVEZg3gcPuBNxH1EvfVYe9h0x/Ptw8KBzv7qxb7l8dg==} + '@esbuild/aix-ppc64@0.27.4': + resolution: {integrity: sha512-cQPwL2mp2nSmHHJlCyoXgHGhbEPMrEEU5xhkcy3Hs/O7nGZqEpZ2sUtLaL9MORLtDfRvVl2/3PAuEkYZH0Ty8Q==} engines: {node: '>=18'} cpu: [ppc64] os: [aix] @@ -1272,8 +1272,8 @@ packages: cpu: [arm64] os: [android] - '@esbuild/android-arm64@0.27.3': - resolution: {integrity: sha512-YdghPYUmj/FX2SYKJ0OZxf+iaKgMsKHVPF1MAq/P8WirnSpCStzKJFjOjzsW0QQ7oIAiccHdcqjbHmJxRb/dmg==} + '@esbuild/android-arm64@0.27.4': + resolution: {integrity: sha512-gdLscB7v75wRfu7QSm/zg6Rx29VLdy9eTr2t44sfTW7CxwAtQghZ4ZnqHk3/ogz7xao0QAgrkradbBzcqFPasw==} engines: {node: '>=18'} cpu: [arm64] os: [android] @@ -1284,8 +1284,8 @@ packages: cpu: [arm] os: [android] - '@esbuild/android-arm@0.27.3': - resolution: {integrity: sha512-i5D1hPY7GIQmXlXhs2w8AWHhenb00+GxjxRncS2ZM7YNVGNfaMxgzSGuO8o8SJzRc/oZwU2bcScvVERk03QhzA==} + '@esbuild/android-arm@0.27.4': + resolution: {integrity: sha512-X9bUgvxiC8CHAGKYufLIHGXPJWnr0OCdR0anD2e21vdvgCI8lIfqFbnoeOz7lBjdrAGUhqLZLcQo6MLhTO2DKQ==} engines: {node: '>=18'} cpu: [arm] os: [android] @@ -1296,8 +1296,8 @@ packages: cpu: [x64] os: [android] - '@esbuild/android-x64@0.27.3': - resolution: {integrity: sha512-IN/0BNTkHtk8lkOM8JWAYFg4ORxBkZQf9zXiEOfERX/CzxW3Vg1ewAhU7QSWQpVIzTW+b8Xy+lGzdYXV6UZObQ==} + '@esbuild/android-x64@0.27.4': + resolution: {integrity: sha512-PzPFnBNVF292sfpfhiyiXCGSn9HZg5BcAz+ivBuSsl6Rk4ga1oEXAamhOXRFyMcjwr2DVtm40G65N3GLeH1Lvw==} engines: {node: '>=18'} cpu: [x64] os: [android] @@ -1308,8 +1308,8 @@ packages: cpu: [arm64] os: [darwin] - '@esbuild/darwin-arm64@0.27.3': - resolution: {integrity: sha512-Re491k7ByTVRy0t3EKWajdLIr0gz2kKKfzafkth4Q8A5n1xTHrkqZgLLjFEHVD+AXdUGgQMq+Godfq45mGpCKg==} + '@esbuild/darwin-arm64@0.27.4': + resolution: {integrity: sha512-b7xaGIwdJlht8ZFCvMkpDN6uiSmnxxK56N2GDTMYPr2/gzvfdQN8rTfBsvVKmIVY/X7EM+/hJKEIbbHs9oA4tQ==} engines: {node: '>=18'} cpu: [arm64] os: [darwin] @@ -1320,8 +1320,8 @@ packages: cpu: [x64] os: [darwin] - '@esbuild/darwin-x64@0.27.3': - resolution: {integrity: sha512-vHk/hA7/1AckjGzRqi6wbo+jaShzRowYip6rt6q7VYEDX4LEy1pZfDpdxCBnGtl+A5zq8iXDcyuxwtv3hNtHFg==} + '@esbuild/darwin-x64@0.27.4': + resolution: {integrity: sha512-sR+OiKLwd15nmCdqpXMnuJ9W2kpy0KigzqScqHI3Hqwr7IXxBp3Yva+yJwoqh7rE8V77tdoheRYataNKL4QrPw==} engines: {node: '>=18'} cpu: [x64] os: [darwin] @@ -1332,8 +1332,8 @@ packages: cpu: [arm64] os: [freebsd] - '@esbuild/freebsd-arm64@0.27.3': - resolution: {integrity: sha512-ipTYM2fjt3kQAYOvo6vcxJx3nBYAzPjgTCk7QEgZG8AUO3ydUhvelmhrbOheMnGOlaSFUoHXB6un+A7q4ygY9w==} + '@esbuild/freebsd-arm64@0.27.4': + resolution: {integrity: sha512-jnfpKe+p79tCnm4GVav68A7tUFeKQwQyLgESwEAUzyxk/TJr4QdGog9sqWNcUbr/bZt/O/HXouspuQDd9JxFSw==} engines: {node: '>=18'} cpu: [arm64] os: [freebsd] @@ -1344,8 +1344,8 @@ packages: cpu: [x64] os: [freebsd] - '@esbuild/freebsd-x64@0.27.3': - resolution: {integrity: sha512-dDk0X87T7mI6U3K9VjWtHOXqwAMJBNN2r7bejDsc+j03SEjtD9HrOl8gVFByeM0aJksoUuUVU9TBaZa2rgj0oA==} + '@esbuild/freebsd-x64@0.27.4': + resolution: {integrity: sha512-2kb4ceA/CpfUrIcTUl1wrP/9ad9Atrp5J94Lq69w7UwOMolPIGrfLSvAKJp0RTvkPPyn6CIWrNy13kyLikZRZQ==} engines: {node: '>=18'} cpu: [x64] os: [freebsd] @@ -1356,8 +1356,8 @@ packages: cpu: [arm64] os: [linux] - '@esbuild/linux-arm64@0.27.3': - resolution: {integrity: sha512-sZOuFz/xWnZ4KH3YfFrKCf1WyPZHakVzTiqji3WDc0BCl2kBwiJLCXpzLzUBLgmp4veFZdvN5ChW4Eq/8Fc2Fg==} + '@esbuild/linux-arm64@0.27.4': + resolution: {integrity: sha512-7nQOttdzVGth1iz57kxg9uCz57dxQLHWxopL6mYuYthohPKEK0vU0C3O21CcBK6KDlkYVcnDXY099HcCDXd9dA==} engines: {node: '>=18'} cpu: [arm64] os: [linux] @@ -1368,8 +1368,8 @@ packages: cpu: [arm] os: [linux] - '@esbuild/linux-arm@0.27.3': - resolution: {integrity: sha512-s6nPv2QkSupJwLYyfS+gwdirm0ukyTFNl3KTgZEAiJDd+iHZcbTPPcWCcRYH+WlNbwChgH2QkE9NSlNrMT8Gfw==} + '@esbuild/linux-arm@0.27.4': + resolution: {integrity: sha512-aBYgcIxX/wd5n2ys0yESGeYMGF+pv6g0DhZr3G1ZG4jMfruU9Tl1i2Z+Wnj9/KjGz1lTLCcorqE2viePZqj4Eg==} engines: {node: '>=18'} cpu: [arm] os: [linux] @@ -1380,8 +1380,8 @@ packages: cpu: [ia32] os: [linux] - '@esbuild/linux-ia32@0.27.3': - resolution: {integrity: sha512-yGlQYjdxtLdh0a3jHjuwOrxQjOZYD/C9PfdbgJJF3TIZWnm/tMd/RcNiLngiu4iwcBAOezdnSLAwQDPqTmtTYg==} + '@esbuild/linux-ia32@0.27.4': + resolution: {integrity: sha512-oPtixtAIzgvzYcKBQM/qZ3R+9TEUd1aNJQu0HhGyqtx6oS7qTpvjheIWBbes4+qu1bNlo2V4cbkISr8q6gRBFA==} engines: {node: '>=18'} cpu: [ia32] os: [linux] @@ -1392,8 +1392,8 @@ packages: cpu: [loong64] os: [linux] - '@esbuild/linux-loong64@0.27.3': - resolution: {integrity: sha512-WO60Sn8ly3gtzhyjATDgieJNet/KqsDlX5nRC5Y3oTFcS1l0KWba+SEa9Ja1GfDqSF1z6hif/SkpQJbL63cgOA==} + '@esbuild/linux-loong64@0.27.4': + resolution: {integrity: sha512-8mL/vh8qeCoRcFH2nM8wm5uJP+ZcVYGGayMavi8GmRJjuI3g1v6Z7Ni0JJKAJW+m0EtUuARb6Lmp4hMjzCBWzA==} engines: {node: '>=18'} cpu: [loong64] os: [linux] @@ -1404,8 +1404,8 @@ packages: cpu: [mips64el] os: [linux] - '@esbuild/linux-mips64el@0.27.3': - resolution: {integrity: sha512-APsymYA6sGcZ4pD6k+UxbDjOFSvPWyZhjaiPyl/f79xKxwTnrn5QUnXR5prvetuaSMsb4jgeHewIDCIWljrSxw==} + '@esbuild/linux-mips64el@0.27.4': + resolution: {integrity: sha512-1RdrWFFiiLIW7LQq9Q2NES+HiD4NyT8Itj9AUeCl0IVCA459WnPhREKgwrpaIfTOe+/2rdntisegiPWn/r/aAw==} engines: {node: '>=18'} cpu: [mips64el] os: [linux] @@ -1416,8 +1416,8 @@ packages: cpu: [ppc64] os: [linux] - '@esbuild/linux-ppc64@0.27.3': - resolution: {integrity: sha512-eizBnTeBefojtDb9nSh4vvVQ3V9Qf9Df01PfawPcRzJH4gFSgrObw+LveUyDoKU3kxi5+9RJTCWlj4FjYXVPEA==} + '@esbuild/linux-ppc64@0.27.4': + resolution: {integrity: sha512-tLCwNG47l3sd9lpfyx9LAGEGItCUeRCWeAx6x2Jmbav65nAwoPXfewtAdtbtit/pJFLUWOhpv0FpS6GQAmPrHA==} engines: {node: '>=18'} cpu: [ppc64] os: [linux] @@ -1428,8 +1428,8 @@ packages: cpu: [riscv64] os: [linux] - '@esbuild/linux-riscv64@0.27.3': - resolution: {integrity: sha512-3Emwh0r5wmfm3ssTWRQSyVhbOHvqegUDRd0WhmXKX2mkHJe1SFCMJhagUleMq+Uci34wLSipf8Lagt4LlpRFWQ==} + '@esbuild/linux-riscv64@0.27.4': + resolution: {integrity: sha512-BnASypppbUWyqjd1KIpU4AUBiIhVr6YlHx/cnPgqEkNoVOhHg+YiSVxM1RLfiy4t9cAulbRGTNCKOcqHrEQLIw==} engines: {node: '>=18'} cpu: [riscv64] os: [linux] @@ -1440,8 +1440,8 @@ packages: cpu: [s390x] os: [linux] - '@esbuild/linux-s390x@0.27.3': - resolution: {integrity: sha512-pBHUx9LzXWBc7MFIEEL0yD/ZVtNgLytvx60gES28GcWMqil8ElCYR4kvbV2BDqsHOvVDRrOxGySBM9Fcv744hw==} + '@esbuild/linux-s390x@0.27.4': + resolution: {integrity: sha512-+eUqgb/Z7vxVLezG8bVB9SfBie89gMueS+I0xYh2tJdw3vqA/0ImZJ2ROeWwVJN59ihBeZ7Tu92dF/5dy5FttA==} engines: {node: '>=18'} cpu: [s390x] os: [linux] @@ -1452,8 +1452,8 @@ packages: cpu: [x64] os: [linux] - '@esbuild/linux-x64@0.27.3': - resolution: {integrity: sha512-Czi8yzXUWIQYAtL/2y6vogER8pvcsOsk5cpwL4Gk5nJqH5UZiVByIY8Eorm5R13gq+DQKYg0+JyQoytLQas4dA==} + '@esbuild/linux-x64@0.27.4': + resolution: {integrity: sha512-S5qOXrKV8BQEzJPVxAwnryi2+Iq5pB40gTEIT69BQONqR7JH1EPIcQ/Uiv9mCnn05jff9umq/5nqzxlqTOg9NA==} engines: {node: '>=18'} cpu: [x64] os: [linux] @@ -1464,8 +1464,8 @@ packages: cpu: [arm64] os: [netbsd] - '@esbuild/netbsd-arm64@0.27.3': - resolution: {integrity: sha512-sDpk0RgmTCR/5HguIZa9n9u+HVKf40fbEUt+iTzSnCaGvY9kFP0YKBWZtJaraonFnqef5SlJ8/TiPAxzyS+UoA==} + '@esbuild/netbsd-arm64@0.27.4': + resolution: {integrity: sha512-xHT8X4sb0GS8qTqiwzHqpY00C95DPAq7nAwX35Ie/s+LO9830hrMd3oX0ZMKLvy7vsonee73x0lmcdOVXFzd6Q==} engines: {node: '>=18'} cpu: [arm64] os: [netbsd] @@ -1476,8 +1476,8 @@ packages: cpu: [x64] os: [netbsd] - '@esbuild/netbsd-x64@0.27.3': - resolution: {integrity: sha512-P14lFKJl/DdaE00LItAukUdZO5iqNH7+PjoBm+fLQjtxfcfFE20Xf5CrLsmZdq5LFFZzb5JMZ9grUwvtVYzjiA==} + '@esbuild/netbsd-x64@0.27.4': + resolution: {integrity: sha512-RugOvOdXfdyi5Tyv40kgQnI0byv66BFgAqjdgtAKqHoZTbTF2QqfQrFwa7cHEORJf6X2ht+l9ABLMP0dnKYsgg==} engines: {node: '>=18'} cpu: [x64] os: [netbsd] @@ -1488,8 +1488,8 @@ packages: cpu: [arm64] os: [openbsd] - '@esbuild/openbsd-arm64@0.27.3': - resolution: {integrity: sha512-AIcMP77AvirGbRl/UZFTq5hjXK+2wC7qFRGoHSDrZ5v5b8DK/GYpXW3CPRL53NkvDqb9D+alBiC/dV0Fb7eJcw==} + '@esbuild/openbsd-arm64@0.27.4': + resolution: {integrity: sha512-2MyL3IAaTX+1/qP0O1SwskwcwCoOI4kV2IBX1xYnDDqthmq5ArrW94qSIKCAuRraMgPOmG0RDTA74mzYNQA9ow==} engines: {node: '>=18'} cpu: [arm64] os: [openbsd] @@ -1500,8 +1500,8 @@ packages: cpu: [x64] os: [openbsd] - '@esbuild/openbsd-x64@0.27.3': - resolution: {integrity: sha512-DnW2sRrBzA+YnE70LKqnM3P+z8vehfJWHXECbwBmH/CU51z6FiqTQTHFenPlHmo3a8UgpLyH3PT+87OViOh1AQ==} + '@esbuild/openbsd-x64@0.27.4': + resolution: {integrity: sha512-u8fg/jQ5aQDfsnIV6+KwLOf1CmJnfu1ShpwqdwC0uA7ZPwFws55Ngc12vBdeUdnuWoQYx/SOQLGDcdlfXhYmXQ==} engines: {node: '>=18'} cpu: [x64] os: [openbsd] @@ -1512,8 +1512,8 @@ packages: cpu: [arm64] os: [openharmony] - '@esbuild/openharmony-arm64@0.27.3': - resolution: {integrity: sha512-NinAEgr/etERPTsZJ7aEZQvvg/A6IsZG/LgZy+81wON2huV7SrK3e63dU0XhyZP4RKGyTm7aOgmQk0bGp0fy2g==} + '@esbuild/openharmony-arm64@0.27.4': + resolution: {integrity: sha512-JkTZrl6VbyO8lDQO3yv26nNr2RM2yZzNrNHEsj9bm6dOwwu9OYN28CjzZkH57bh4w0I2F7IodpQvUAEd1mbWXg==} engines: {node: '>=18'} cpu: [arm64] os: [openharmony] @@ -1524,8 +1524,8 @@ packages: cpu: [x64] os: [sunos] - '@esbuild/sunos-x64@0.27.3': - resolution: {integrity: sha512-PanZ+nEz+eWoBJ8/f8HKxTTD172SKwdXebZ0ndd953gt1HRBbhMsaNqjTyYLGLPdoWHy4zLU7bDVJztF5f3BHA==} + '@esbuild/sunos-x64@0.27.4': + resolution: {integrity: sha512-/gOzgaewZJfeJTlsWhvUEmUG4tWEY2Spp5M20INYRg2ZKl9QPO3QEEgPeRtLjEWSW8FilRNacPOg8R1uaYkA6g==} engines: {node: '>=18'} cpu: [x64] os: [sunos] @@ -1536,8 +1536,8 @@ packages: cpu: [arm64] os: [win32] - '@esbuild/win32-arm64@0.27.3': - resolution: {integrity: sha512-B2t59lWWYrbRDw/tjiWOuzSsFh1Y/E95ofKz7rIVYSQkUYBjfSgf6oeYPNWHToFRr2zx52JKApIcAS/D5TUBnA==} + '@esbuild/win32-arm64@0.27.4': + resolution: {integrity: sha512-Z9SExBg2y32smoDQdf1HRwHRt6vAHLXcxD2uGgO/v2jK7Y718Ix4ndsbNMU/+1Qiem9OiOdaqitioZwxivhXYg==} engines: {node: '>=18'} cpu: [arm64] os: [win32] @@ -1548,8 +1548,8 @@ packages: cpu: [ia32] os: [win32] - '@esbuild/win32-ia32@0.27.3': - resolution: {integrity: sha512-QLKSFeXNS8+tHW7tZpMtjlNb7HKau0QDpwm49u0vUp9y1WOF+PEzkU84y9GqYaAVW8aH8f3GcBck26jh54cX4Q==} + '@esbuild/win32-ia32@0.27.4': + resolution: {integrity: sha512-DAyGLS0Jz5G5iixEbMHi5KdiApqHBWMGzTtMiJ72ZOLhbu/bzxgAe8Ue8CTS3n3HbIUHQz/L51yMdGMeoxXNJw==} engines: {node: '>=18'} cpu: [ia32] os: [win32] @@ -1560,8 +1560,8 @@ packages: cpu: [x64] os: [win32] - '@esbuild/win32-x64@0.27.3': - resolution: {integrity: sha512-4uJGhsxuptu3OcpVAzli+/gWusVGwZZHTlS63hh++ehExkVT8SgiEf7/uC/PclrPPkLhZqGgCTjd0VWLo6xMqA==} + '@esbuild/win32-x64@0.27.4': + resolution: {integrity: sha512-+knoa0BDoeXgkNvvV1vvbZX4+hizelrkwmGJBdT17t8FNPwG2lKemmuMZlmaNQ3ws3DKKCxpb4zRZEIp3UxFCg==} engines: {node: '>=18'} cpu: [x64] os: [win32] @@ -2313,6 +2313,9 @@ packages: '@standard-schema/spec@1.0.0': resolution: {integrity: sha512-m2bOd0f2RT9k8QJx1JN85cZYyH1RqFBdlwtkSlf4tBDYLCiiZnv1fIIwacK6cqwXavOydf0NPToMQgpKq+dVlA==} + '@standard-schema/spec@1.1.0': + resolution: {integrity: sha512-l2aFy5jALhniG5HgqrD6jXLi/rUWrKvqN/qJx6yoJsgKhblVd+iqqU4RCXavm/jPityDo5TCvKMnpjKnOriy0w==} + '@surma/rollup-plugin-off-main-thread@2.2.3': resolution: {integrity: sha512-lR8q/9W7hZpMWweNiAKU7NQerBnzQQLvi8qnTDU/fxItPhtZVMbPV3lbCwjhIlNBe9Bbr5V+KHshvWmVSG9cxQ==} @@ -2836,41 +2839,41 @@ packages: '@ungap/structured-clone@1.3.0': resolution: {integrity: sha512-WmoN8qaIAo7WTYWbAZuG8PYEhn5fkz7dZrqTBZ7dtt//lL2Gwms1IcnQ5yHqjDfX8Ft5j4YzDM23f87zBfDe9g==} - '@vitejs/plugin-vue@6.0.4': - resolution: {integrity: sha512-uM5iXipgYIn13UUQCZNdWkYk+sysBeA97d5mHsAoAt1u/wpN3+zxOmsVJWosuzX+IMGRzeYUNytztrYznboIkQ==} + '@vitejs/plugin-vue@6.0.5': + resolution: {integrity: sha512-bL3AxKuQySfk1iGcBsQnoRVexTPJq0Z/ixFVM8OhVJAP6ZXXXLtM7NFKWhLl30Kg7uTBqIaPXbh+nuQCuBDedg==} engines: {node: ^20.19.0 || >=22.12.0} peerDependencies: - vite: ^5.0.0 || ^6.0.0 || ^7.0.0 || ^8.0.0-0 + vite: ^5.0.0 || ^6.0.0 || ^7.0.0 || ^8.0.0 vue: ^3.2.25 - '@vitest/expect@4.0.18': - resolution: {integrity: sha512-8sCWUyckXXYvx4opfzVY03EOiYVxyNrHS5QxX3DAIi5dpJAAkyJezHCP77VMX4HKA2LDT/Jpfo8i2r5BE3GnQQ==} + '@vitest/expect@4.1.0': + resolution: {integrity: sha512-EIxG7k4wlWweuCLG9Y5InKFwpMEOyrMb6ZJ1ihYu02LVj/bzUwn2VMU+13PinsjRW75XnITeFrQBMH5+dLvCDA==} - '@vitest/mocker@4.0.18': - resolution: {integrity: sha512-HhVd0MDnzzsgevnOWCBj5Otnzobjy5wLBe4EdeeFGv8luMsGcYqDuFRMcttKWZA5vVO8RFjexVovXvAM4JoJDQ==} + '@vitest/mocker@4.1.0': + resolution: {integrity: sha512-evxREh+Hork43+Y4IOhTo+h5lGmVRyjqI739Rz4RlUPqwrkFFDF6EMvOOYjTx4E8Tl6gyCLRL8Mu7Ry12a13Tw==} peerDependencies: msw: ^2.4.9 - vite: ^6.0.0 || ^7.0.0-0 + vite: ^6.0.0 || ^7.0.0 || ^8.0.0-0 peerDependenciesMeta: msw: optional: true vite: optional: true - '@vitest/pretty-format@4.0.18': - resolution: {integrity: sha512-P24GK3GulZWC5tz87ux0m8OADrQIUVDPIjjj65vBXYG17ZeU3qD7r+MNZ1RNv4l8CGU2vtTRqixrOi9fYk/yKw==} + '@vitest/pretty-format@4.1.0': + resolution: {integrity: sha512-3RZLZlh88Ib0J7NQTRATfc/3ZPOnSUn2uDBUoGNn5T36+bALixmzphN26OUD3LRXWkJu4H0s5vvUeqBiw+kS0A==} - '@vitest/runner@4.0.18': - resolution: {integrity: sha512-rpk9y12PGa22Jg6g5M3UVVnTS7+zycIGk9ZNGN+m6tZHKQb7jrP7/77WfZy13Y/EUDd52NDsLRQhYKtv7XfPQw==} + '@vitest/runner@4.1.0': + resolution: {integrity: sha512-Duvx2OzQ7d6OjchL+trw+aSrb9idh7pnNfxrklo14p3zmNL4qPCDeIJAK+eBKYjkIwG96Bc6vYuxhqDXQOWpoQ==} - '@vitest/snapshot@4.0.18': - resolution: {integrity: sha512-PCiV0rcl7jKQjbgYqjtakly6T1uwv/5BQ9SwBLekVg/EaYeQFPiXcgrC2Y7vDMA8dM1SUEAEV82kgSQIlXNMvA==} + '@vitest/snapshot@4.1.0': + resolution: {integrity: sha512-0Vy9euT1kgsnj1CHttwi9i9o+4rRLEaPRSOJ5gyv579GJkNpgJK+B4HSv/rAWixx2wdAFci1X4CEPjiu2bXIMg==} - '@vitest/spy@4.0.18': - resolution: {integrity: sha512-cbQt3PTSD7P2OARdVW3qWER5EGq7PHlvE+QfzSC0lbwO+xnt7+XH06ZzFjFRgzUX//JmpxrCu92VdwvEPlWSNw==} + '@vitest/spy@4.1.0': + resolution: {integrity: sha512-pz77k+PgNpyMDv2FV6qmk5ZVau6c3R8HC8v342T2xlFxQKTrSeYw9waIJG8KgV9fFwAtTu4ceRzMivPTH6wSxw==} - '@vitest/utils@4.0.18': - resolution: {integrity: sha512-msMRKLMVLWygpK3u2Hybgi4MNjcYJvwTb0Ru09+fOyCXIgT5raYP041DRRdiJiI3k/2U6SEbAETB3YtBrUkCFA==} + '@vitest/utils@4.1.0': + resolution: {integrity: sha512-XfPXT6a8TZY3dcGY8EdwsBulFCIw+BeeX0RZn2x/BtiY/75YGh8FeWGG8QISN/WhaqSrE2OrlDgtF8q5uhOTmw==} '@volar/language-core@2.4.28': resolution: {integrity: sha512-w4qhIJ8ZSitgLAkVay6AbcnC7gP3glYM3fYwKV3srj8m494E3xtrCv6E+bWviiK/8hs6e6t1ij1s2Endql7vzQ==} @@ -2915,22 +2918,22 @@ packages: '@vue/devtools-api@7.7.7': resolution: {integrity: sha512-lwOnNBH2e7x1fIIbVT7yF5D+YWhqELm55/4ZKf45R9T8r9dE2AIOy8HKjfqzGsoTHFbWbr337O4E0A0QADnjBg==} - '@vue/devtools-core@8.0.7': - resolution: {integrity: sha512-PmpiPxvg3Of80ODHVvyckxwEW1Z02VIAvARIZS1xegINn3VuNQLm9iHUmKD+o6cLkMNWV8OG8x7zo0kgydZgdg==} + '@vue/devtools-core@8.1.0': + resolution: {integrity: sha512-LvD1VgDpoHmYL00IgKRLKktF6SsPAb0yaV8wB8q2jRwsAWvqhS8+vsMLEGKNs7uoKyymXhT92dhxgf/wir6YGQ==} peerDependencies: vue: ^3.0.0 '@vue/devtools-kit@7.7.7': resolution: {integrity: sha512-wgoZtxcTta65cnZ1Q6MbAfePVFxfM+gq0saaeytoph7nEa7yMXoi6sCPy4ufO111B9msnw0VOWjPEFCXuAKRHA==} - '@vue/devtools-kit@8.0.7': - resolution: {integrity: sha512-H6esJGHGl5q0E9iV3m2EoBQHJ+V83WMW83A0/+Fn95eZ2iIvdsq4+UCS6yT/Fdd4cGZSchx/MdWDreM3WqMsDw==} + '@vue/devtools-kit@8.1.0': + resolution: {integrity: sha512-/NZlS4WtGIB54DA/z10gzk+n/V7zaqSzYZOVlg2CfdnpIKdB61bd7JDIMxf/zrtX41zod8E2/bbEBoW/d7x70Q==} '@vue/devtools-shared@7.7.7': resolution: {integrity: sha512-+udSj47aRl5aKb0memBvcUG9koarqnxNM5yjuREvqwK6T3ap4mn3Zqqc17QrBFTqSMjr3HK1cvStEZpMDpfdyw==} - '@vue/devtools-shared@8.0.7': - resolution: {integrity: sha512-CgAb9oJH5NUmbQRdYDj/1zMiaICYSLtm+B1kxcP72LBrifGAjUmt8bx52dDH1gWRPlQgxGPqpAMKavzVirAEhA==} + '@vue/devtools-shared@8.1.0': + resolution: {integrity: sha512-h8uCb4Qs8UT8VdTT5yjY6tOJ//qH7EpxToixR0xqejR55t5OdISIg7AJ7eBkhBs8iu1qG5gY3QQNN1DF1EelAA==} '@vue/eslint-config-typescript@14.7.0': resolution: {integrity: sha512-iegbMINVc+seZ/QxtzWiOBozctrHiF2WvGedruu2EbLujg9VuU0FQiNcN2z1ycuaoKKpF4m2qzB5HDEMKbxtIg==} @@ -3280,8 +3283,8 @@ packages: resolution: {integrity: sha512-8WB3Jcas3swSvjIeA2yvCJ+Miyz5l1ZmB6HFb9R1317dt9LCQoswg/BGrmAmkWVEszSrrg4RwmO46qIm2OEnSA==} engines: {node: '>=16'} - caniuse-lite@1.0.30001777: - resolution: {integrity: sha512-tmN+fJxroPndC74efCdp12j+0rk0RHwV5Jwa1zWaFVyw2ZxAuPeG8ZgWC3Wz7uSjT3qMRQ5XHZ4COgQmsCMJAQ==} + caniuse-lite@1.0.30001778: + resolution: {integrity: sha512-PN7uxFL+ExFJO61aVmP1aIEG4i9whQd4eoSCebav62UwDyp5OHh06zN4jqKSMePVgxHifCw1QJxdRkA1Pisekg==} capture-website@4.2.0: resolution: {integrity: sha512-EmkSn36CXTC8tUsS6aNmvvsdpfVTYYkuRp7U5bV9gcJwcDbqqA5c0Op/iskYPKtDdOkuVp61mjn/LLywX0h7cw==} @@ -3742,6 +3745,9 @@ packages: es-module-lexer@1.7.0: resolution: {integrity: sha512-jEQoCwk8hyb2AZziIOLhDqpm5+2ww5uIE6lkO/6jcOCusfk6LhMHpXXfBLXTZ7Ydyt0j4VoUQv6uGNYbdW+kBA==} + es-module-lexer@2.0.0: + resolution: {integrity: sha512-5POEcUuZybH7IdmGsD8wlf0AI55wMecM9rVBTI/qEAy2c1kTOm3DjFYjrBdI2K3BaJjJYfYFeRtM0t9ssnRuxw==} + es-object-atoms@1.1.1: resolution: {integrity: sha512-FGgH2h8zKNim9ljj7dankFPcICIK9Cp5bm+c2gQSYePhpaG5+esrLODihIorn+Pe6FGJzWhXQotPv73jTaldXA==} engines: {node: '>= 0.4'} @@ -3759,8 +3765,8 @@ packages: engines: {node: '>=18'} hasBin: true - esbuild@0.27.3: - resolution: {integrity: sha512-8VwMnyGCONIs6cWue2IdpHxHnAjzxnw2Zr7MkVxB2vjmQ2ivqGFb4LEG3SMnv0Gb2F/G/2yA8zUaiL1gywDCCg==} + esbuild@0.27.4: + resolution: {integrity: sha512-Rq4vbHnYkK5fws5NF7MYTU68FPRE1ajX7heQ/8QXXWqNgqqJ/GkmmyxIzUnf2Sr/bakf8l54716CcMGHYhMrrQ==} engines: {node: '>=18'} hasBin: true @@ -4155,8 +4161,8 @@ packages: resolution: {integrity: sha512-5v6yZd4JK3eMI3FqqCouswVqwugaA9r4dNZB1wwcmrD02QkV5H0y7XBQW8QwQqEaZY1pM9aqORSORhJRdNK44Q==} engines: {node: '>=6.0'} - happy-dom@20.8.3: - resolution: {integrity: sha512-lMHQRRwIPyJ70HV0kkFT7jH/gXzSI7yDkQFe07E2flwmNDFoWUTRMKpW2sglsnpeA7b6S2TJPp98EbQxai8eaQ==} + happy-dom@20.8.4: + resolution: {integrity: sha512-GKhjq4OQCYB4VLFBzv8mmccUadwlAusOZOI7hC1D9xDIT5HhzkJK17c4el2f6R6C715P9xB4uiMxeKUa2nHMwQ==} engines: {node: '>=20.0.0'} hard-rejection@2.1.0: @@ -5918,8 +5924,8 @@ packages: resolution: {integrity: sha512-OpZ3zP+jT1PI7I8nemJX4AKmAX070ZkYPVWV/AaKTJl+tXCTGyVdC1a4SL8RUQYEwk/f34ZX8UTykN68FwrqAA==} engines: {node: '>= 0.6'} - std-env@3.10.0: - resolution: {integrity: sha512-5GS12FdOZNliM5mAOxFRg7Ir0pWz8MdpYm6AY6VPkGpbA7ZzmbzNcBJQ0GPvvyWgcY7QAhCgf9Uy89I03faLkg==} + std-env@4.0.0: + resolution: {integrity: sha512-zUMPtQ/HBY3/50VbpkupYHbRroTRZJPRLvreamgErJVys0ceuzMkD44J/QjqhHjOzK42GQ3QZIeFG1OYfOtKqQ==} streamx@2.22.0: resolution: {integrity: sha512-sLh1evHOzBy/iWRiR6d1zRcLao4gGZr3C1kzNz4fopCOKJb6xD9ub8Mpi9Mr1R6id5o43S+d93fI48UC5uM9aw==} @@ -6464,11 +6470,11 @@ packages: '@vite-pwa/assets-generator': optional: true - vite-plugin-vue-devtools@8.0.7: - resolution: {integrity: sha512-BWj/ykGpqVAJVdPyHmSTUm44buz3jPv+6jnvuFdQSRH0kAgP1cEIE4doHiFyqHXOmuB5EQVR/nh2g9YRiRNs9g==} + vite-plugin-vue-devtools@8.1.0: + resolution: {integrity: sha512-4AvNRePfni3+PqOunACmAImC6SJVpUv6f7/g4oakyre9hYdEMrvDYlNmTZQsJPzVLMcGzn1FvSEqJ/n4HQ9cDg==} engines: {node: '>=v14.21.3'} peerDependencies: - vite: ^6.0.0 || ^7.0.0-0 || ^8.0.0-0 + vite: ^6.0.0 || ^7.0.0 || ^8.0.0 vite-plugin-vue-inspector@5.3.2: resolution: {integrity: sha512-YvEKooQcSiBTAs0DoYLfefNja9bLgkFM7NI2b07bE2SruuvX0MEa9cMaxjKVMkeCp5Nz9FRIdcN1rOdFVBeL6Q==} @@ -6520,20 +6526,21 @@ packages: yaml: optional: true - vitest@4.0.18: - resolution: {integrity: sha512-hOQuK7h0FGKgBAas7v0mSAsnvrIgAvWmRFjmzpJ7SwFHH3g1k2u37JtYwOwmEKhK6ZO3v9ggDBBm0La1LCK4uQ==} + vitest@4.1.0: + resolution: {integrity: sha512-YbDrMF9jM2Lqc++2530UourxZHmkKLxrs4+mYhEwqWS97WJ7wOYEkcr+QfRgJ3PW9wz3odRijLZjHEaRLTNbqw==} engines: {node: ^20.0.0 || ^22.0.0 || >=24.0.0} hasBin: true peerDependencies: '@edge-runtime/vm': '*' '@opentelemetry/api': ^1.9.0 '@types/node': ^20.0.0 || ^22.0.0 || >=24.0.0 - '@vitest/browser-playwright': 4.0.18 - '@vitest/browser-preview': 4.0.18 - '@vitest/browser-webdriverio': 4.0.18 - '@vitest/ui': 4.0.18 + '@vitest/browser-playwright': 4.1.0 + '@vitest/browser-preview': 4.1.0 + '@vitest/browser-webdriverio': 4.1.0 + '@vitest/ui': 4.1.0 happy-dom: '*' jsdom: '*' + vite: ^6.0.0 || ^7.0.0 || ^8.0.0-0 peerDependenciesMeta: '@edge-runtime/vm': optional: true @@ -8001,157 +8008,157 @@ snapshots: '@esbuild/aix-ppc64@0.25.12': optional: true - '@esbuild/aix-ppc64@0.27.3': + '@esbuild/aix-ppc64@0.27.4': optional: true '@esbuild/android-arm64@0.25.12': optional: true - '@esbuild/android-arm64@0.27.3': + '@esbuild/android-arm64@0.27.4': optional: true '@esbuild/android-arm@0.25.12': optional: true - '@esbuild/android-arm@0.27.3': + '@esbuild/android-arm@0.27.4': optional: true '@esbuild/android-x64@0.25.12': optional: true - '@esbuild/android-x64@0.27.3': + '@esbuild/android-x64@0.27.4': optional: true '@esbuild/darwin-arm64@0.25.12': optional: true - '@esbuild/darwin-arm64@0.27.3': + '@esbuild/darwin-arm64@0.27.4': optional: true '@esbuild/darwin-x64@0.25.12': optional: true - '@esbuild/darwin-x64@0.27.3': + '@esbuild/darwin-x64@0.27.4': optional: true '@esbuild/freebsd-arm64@0.25.12': optional: true - '@esbuild/freebsd-arm64@0.27.3': + '@esbuild/freebsd-arm64@0.27.4': optional: true '@esbuild/freebsd-x64@0.25.12': optional: true - '@esbuild/freebsd-x64@0.27.3': + '@esbuild/freebsd-x64@0.27.4': optional: true '@esbuild/linux-arm64@0.25.12': optional: true - '@esbuild/linux-arm64@0.27.3': + '@esbuild/linux-arm64@0.27.4': optional: true '@esbuild/linux-arm@0.25.12': optional: true - '@esbuild/linux-arm@0.27.3': + '@esbuild/linux-arm@0.27.4': optional: true '@esbuild/linux-ia32@0.25.12': optional: true - '@esbuild/linux-ia32@0.27.3': + '@esbuild/linux-ia32@0.27.4': optional: true '@esbuild/linux-loong64@0.25.12': optional: true - '@esbuild/linux-loong64@0.27.3': + '@esbuild/linux-loong64@0.27.4': optional: true '@esbuild/linux-mips64el@0.25.12': optional: true - '@esbuild/linux-mips64el@0.27.3': + '@esbuild/linux-mips64el@0.27.4': optional: true '@esbuild/linux-ppc64@0.25.12': optional: true - '@esbuild/linux-ppc64@0.27.3': + '@esbuild/linux-ppc64@0.27.4': optional: true '@esbuild/linux-riscv64@0.25.12': optional: true - '@esbuild/linux-riscv64@0.27.3': + '@esbuild/linux-riscv64@0.27.4': optional: true '@esbuild/linux-s390x@0.25.12': optional: true - '@esbuild/linux-s390x@0.27.3': + '@esbuild/linux-s390x@0.27.4': optional: true '@esbuild/linux-x64@0.25.12': optional: true - '@esbuild/linux-x64@0.27.3': + '@esbuild/linux-x64@0.27.4': optional: true '@esbuild/netbsd-arm64@0.25.12': optional: true - '@esbuild/netbsd-arm64@0.27.3': + '@esbuild/netbsd-arm64@0.27.4': optional: true '@esbuild/netbsd-x64@0.25.12': optional: true - '@esbuild/netbsd-x64@0.27.3': + '@esbuild/netbsd-x64@0.27.4': optional: true '@esbuild/openbsd-arm64@0.25.12': optional: true - '@esbuild/openbsd-arm64@0.27.3': + '@esbuild/openbsd-arm64@0.27.4': optional: true '@esbuild/openbsd-x64@0.25.12': optional: true - '@esbuild/openbsd-x64@0.27.3': + '@esbuild/openbsd-x64@0.27.4': optional: true '@esbuild/openharmony-arm64@0.25.12': optional: true - '@esbuild/openharmony-arm64@0.27.3': + '@esbuild/openharmony-arm64@0.27.4': optional: true '@esbuild/sunos-x64@0.25.12': optional: true - '@esbuild/sunos-x64@0.27.3': + '@esbuild/sunos-x64@0.27.4': optional: true '@esbuild/win32-arm64@0.25.12': optional: true - '@esbuild/win32-arm64@0.27.3': + '@esbuild/win32-arm64@0.27.4': optional: true '@esbuild/win32-ia32@0.25.12': optional: true - '@esbuild/win32-ia32@0.27.3': + '@esbuild/win32-ia32@0.27.4': optional: true '@esbuild/win32-x64@0.25.12': optional: true - '@esbuild/win32-x64@0.27.3': + '@esbuild/win32-x64@0.27.4': optional: true '@eslint-community/eslint-utils@4.9.0(eslint@9.39.4(jiti@2.4.2))': @@ -8888,6 +8895,8 @@ snapshots: '@standard-schema/spec@1.0.0': {} + '@standard-schema/spec@1.1.0': {} + '@surma/rollup-plugin-off-main-thread@2.2.3': dependencies: ejs: 3.1.10 @@ -9476,49 +9485,51 @@ snapshots: '@ungap/structured-clone@1.3.0': {} - '@vitejs/plugin-vue@6.0.4(vite@7.3.1(@types/node@24.12.0)(jiti@2.4.2)(lightningcss@1.31.1)(sass-embedded@1.98.0)(sass@1.98.0)(terser@5.31.6)(yaml@2.5.0))(vue@3.5.27(typescript@5.9.3))': + '@vitejs/plugin-vue@6.0.5(vite@7.3.1(@types/node@24.12.0)(jiti@2.4.2)(lightningcss@1.31.1)(sass-embedded@1.98.0)(sass@1.98.0)(terser@5.31.6)(yaml@2.5.0))(vue@3.5.27(typescript@5.9.3))': dependencies: '@rolldown/pluginutils': 1.0.0-rc.2 vite: 7.3.1(@types/node@24.12.0)(jiti@2.4.2)(lightningcss@1.31.1)(sass-embedded@1.98.0)(sass@1.98.0)(terser@5.31.6)(yaml@2.5.0) vue: 3.5.27(typescript@5.9.3) - '@vitest/expect@4.0.18': + '@vitest/expect@4.1.0': dependencies: - '@standard-schema/spec': 1.0.0 + '@standard-schema/spec': 1.1.0 '@types/chai': 5.2.2 - '@vitest/spy': 4.0.18 - '@vitest/utils': 4.0.18 + '@vitest/spy': 4.1.0 + '@vitest/utils': 4.1.0 chai: 6.2.2 tinyrainbow: 3.0.3 - '@vitest/mocker@4.0.18(vite@7.3.1(@types/node@24.12.0)(jiti@2.4.2)(lightningcss@1.31.1)(sass-embedded@1.98.0)(sass@1.98.0)(terser@5.31.6)(yaml@2.5.0))': + '@vitest/mocker@4.1.0(vite@7.3.1(@types/node@24.12.0)(jiti@2.4.2)(lightningcss@1.31.1)(sass-embedded@1.98.0)(sass@1.98.0)(terser@5.31.6)(yaml@2.5.0))': dependencies: - '@vitest/spy': 4.0.18 + '@vitest/spy': 4.1.0 estree-walker: 3.0.3 magic-string: 0.30.21 optionalDependencies: vite: 7.3.1(@types/node@24.12.0)(jiti@2.4.2)(lightningcss@1.31.1)(sass-embedded@1.98.0)(sass@1.98.0)(terser@5.31.6)(yaml@2.5.0) - '@vitest/pretty-format@4.0.18': + '@vitest/pretty-format@4.1.0': dependencies: tinyrainbow: 3.0.3 - '@vitest/runner@4.0.18': + '@vitest/runner@4.1.0': dependencies: - '@vitest/utils': 4.0.18 + '@vitest/utils': 4.1.0 pathe: 2.0.3 - '@vitest/snapshot@4.0.18': + '@vitest/snapshot@4.1.0': dependencies: - '@vitest/pretty-format': 4.0.18 + '@vitest/pretty-format': 4.1.0 + '@vitest/utils': 4.1.0 magic-string: 0.30.21 pathe: 2.0.3 - '@vitest/spy@4.0.18': {} + '@vitest/spy@4.1.0': {} - '@vitest/utils@4.0.18': + '@vitest/utils@4.1.0': dependencies: - '@vitest/pretty-format': 4.0.18 + '@vitest/pretty-format': 4.1.0 + convert-source-map: 2.0.0 tinyrainbow: 3.0.3 '@volar/language-core@2.4.28': @@ -9599,10 +9610,10 @@ snapshots: dependencies: '@vue/devtools-kit': 7.7.7 - '@vue/devtools-core@8.0.7(vue@3.5.27(typescript@5.9.3))': + '@vue/devtools-core@8.1.0(vue@3.5.27(typescript@5.9.3))': dependencies: - '@vue/devtools-kit': 8.0.7 - '@vue/devtools-shared': 8.0.7 + '@vue/devtools-kit': 8.1.0 + '@vue/devtools-shared': 8.1.0 vue: 3.5.27(typescript@5.9.3) '@vue/devtools-kit@7.7.7': @@ -9615,9 +9626,9 @@ snapshots: speakingurl: 14.0.1 superjson: 2.2.2 - '@vue/devtools-kit@8.0.7': + '@vue/devtools-kit@8.1.0': dependencies: - '@vue/devtools-shared': 8.0.7 + '@vue/devtools-shared': 8.1.0 birpc: 2.6.1 hookable: 5.5.3 perfect-debounce: 2.0.0 @@ -9626,7 +9637,7 @@ snapshots: dependencies: rfdc: 1.4.1 - '@vue/devtools-shared@8.0.7': {} + '@vue/devtools-shared@8.1.0': {} '@vue/eslint-config-typescript@14.7.0(eslint-plugin-vue@10.8.0(@typescript-eslint/parser@8.57.0(eslint@9.39.4(jiti@2.4.2))(typescript@5.9.3))(eslint@9.39.4(jiti@2.4.2))(vue-eslint-parser@10.4.0(eslint@9.39.4(jiti@2.4.2))))(eslint@9.39.4(jiti@2.4.2))(typescript@5.9.3)': dependencies: @@ -9811,7 +9822,7 @@ snapshots: autoprefixer@10.4.27(postcss@8.5.8): dependencies: browserslist: 4.28.1 - caniuse-lite: 1.0.30001777 + caniuse-lite: 1.0.30001778 fraction.js: 5.3.4 picocolors: 1.1.1 postcss: 8.5.8 @@ -9930,7 +9941,7 @@ snapshots: browserslist@4.28.1: dependencies: baseline-browser-mapping: 2.9.4 - caniuse-lite: 1.0.30001777 + caniuse-lite: 1.0.30001778 electron-to-chromium: 1.5.266 node-releases: 2.0.27 update-browserslist-db: 1.2.2(browserslist@4.28.1) @@ -9992,7 +10003,7 @@ snapshots: camelcase@8.0.0: {} - caniuse-lite@1.0.30001777: {} + caniuse-lite@1.0.30001778: {} capture-website@4.2.0(typescript@5.9.3): dependencies: @@ -10457,6 +10468,8 @@ snapshots: es-module-lexer@1.7.0: {} + es-module-lexer@2.0.0: {} + es-object-atoms@1.1.1: dependencies: es-errors: 1.3.0 @@ -10503,34 +10516,34 @@ snapshots: '@esbuild/win32-ia32': 0.25.12 '@esbuild/win32-x64': 0.25.12 - esbuild@0.27.3: + esbuild@0.27.4: optionalDependencies: - '@esbuild/aix-ppc64': 0.27.3 - '@esbuild/android-arm': 0.27.3 - '@esbuild/android-arm64': 0.27.3 - '@esbuild/android-x64': 0.27.3 - '@esbuild/darwin-arm64': 0.27.3 - '@esbuild/darwin-x64': 0.27.3 - '@esbuild/freebsd-arm64': 0.27.3 - '@esbuild/freebsd-x64': 0.27.3 - '@esbuild/linux-arm': 0.27.3 - '@esbuild/linux-arm64': 0.27.3 - '@esbuild/linux-ia32': 0.27.3 - '@esbuild/linux-loong64': 0.27.3 - '@esbuild/linux-mips64el': 0.27.3 - '@esbuild/linux-ppc64': 0.27.3 - '@esbuild/linux-riscv64': 0.27.3 - '@esbuild/linux-s390x': 0.27.3 - '@esbuild/linux-x64': 0.27.3 - '@esbuild/netbsd-arm64': 0.27.3 - '@esbuild/netbsd-x64': 0.27.3 - '@esbuild/openbsd-arm64': 0.27.3 - '@esbuild/openbsd-x64': 0.27.3 - '@esbuild/openharmony-arm64': 0.27.3 - '@esbuild/sunos-x64': 0.27.3 - '@esbuild/win32-arm64': 0.27.3 - '@esbuild/win32-ia32': 0.27.3 - '@esbuild/win32-x64': 0.27.3 + '@esbuild/aix-ppc64': 0.27.4 + '@esbuild/android-arm': 0.27.4 + '@esbuild/android-arm64': 0.27.4 + '@esbuild/android-x64': 0.27.4 + '@esbuild/darwin-arm64': 0.27.4 + '@esbuild/darwin-x64': 0.27.4 + '@esbuild/freebsd-arm64': 0.27.4 + '@esbuild/freebsd-x64': 0.27.4 + '@esbuild/linux-arm': 0.27.4 + '@esbuild/linux-arm64': 0.27.4 + '@esbuild/linux-ia32': 0.27.4 + '@esbuild/linux-loong64': 0.27.4 + '@esbuild/linux-mips64el': 0.27.4 + '@esbuild/linux-ppc64': 0.27.4 + '@esbuild/linux-riscv64': 0.27.4 + '@esbuild/linux-s390x': 0.27.4 + '@esbuild/linux-x64': 0.27.4 + '@esbuild/netbsd-arm64': 0.27.4 + '@esbuild/netbsd-x64': 0.27.4 + '@esbuild/openbsd-arm64': 0.27.4 + '@esbuild/openbsd-x64': 0.27.4 + '@esbuild/openharmony-arm64': 0.27.4 + '@esbuild/sunos-x64': 0.27.4 + '@esbuild/win32-arm64': 0.27.4 + '@esbuild/win32-ia32': 0.27.4 + '@esbuild/win32-x64': 0.27.4 escalade@3.2.0: {} @@ -10970,7 +10983,7 @@ snapshots: section-matter: 1.0.0 strip-bom-string: 1.0.0 - happy-dom@20.8.3: + happy-dom@20.8.4: dependencies: '@types/node': 24.12.0 '@types/whatwg-mimetype': 3.0.2 @@ -12846,7 +12859,7 @@ snapshots: statuses@1.5.0: {} - std-env@3.10.0: {} + std-env@4.0.0: {} streamx@2.22.0: dependencies: @@ -13489,11 +13502,11 @@ snapshots: transitivePeerDependencies: - supports-color - vite-plugin-vue-devtools@8.0.7(vite@7.3.1(@types/node@24.12.0)(jiti@2.4.2)(lightningcss@1.31.1)(sass-embedded@1.98.0)(sass@1.98.0)(terser@5.31.6)(yaml@2.5.0))(vue@3.5.27(typescript@5.9.3)): + vite-plugin-vue-devtools@8.1.0(vite@7.3.1(@types/node@24.12.0)(jiti@2.4.2)(lightningcss@1.31.1)(sass-embedded@1.98.0)(sass@1.98.0)(terser@5.31.6)(yaml@2.5.0))(vue@3.5.27(typescript@5.9.3)): dependencies: - '@vue/devtools-core': 8.0.7(vue@3.5.27(typescript@5.9.3)) - '@vue/devtools-kit': 8.0.7 - '@vue/devtools-shared': 8.0.7 + '@vue/devtools-core': 8.1.0(vue@3.5.27(typescript@5.9.3)) + '@vue/devtools-kit': 8.1.0 + '@vue/devtools-shared': 8.1.0 sirv: 3.0.2 vite: 7.3.1(@types/node@24.12.0)(jiti@2.4.2)(lightningcss@1.31.1)(sass-embedded@1.98.0)(sass@1.98.0)(terser@5.31.6)(yaml@2.5.0) vite-plugin-inspect: 11.3.3(vite@7.3.1(@types/node@24.12.0)(jiti@2.4.2)(lightningcss@1.31.1)(sass-embedded@1.98.0)(sass@1.98.0)(terser@5.31.6)(yaml@2.5.0)) @@ -13528,7 +13541,7 @@ snapshots: vite@7.3.1(@types/node@24.12.0)(jiti@2.4.2)(lightningcss@1.31.1)(sass-embedded@1.98.0)(sass@1.98.0)(terser@5.31.6)(yaml@2.5.0): dependencies: - esbuild: 0.27.3 + esbuild: 0.27.4 fdir: 6.5.0(picomatch@4.0.3) picomatch: 4.0.3 postcss: 8.5.8 @@ -13544,22 +13557,22 @@ snapshots: terser: 5.31.6 yaml: 2.5.0 - vitest@4.0.18(@types/node@24.12.0)(happy-dom@20.8.3)(jiti@2.4.2)(jsdom@27.4.0)(lightningcss@1.31.1)(sass-embedded@1.98.0)(sass@1.98.0)(terser@5.31.6)(yaml@2.5.0): + vitest@4.1.0(@types/node@24.12.0)(happy-dom@20.8.4)(jsdom@27.4.0)(vite@7.3.1(@types/node@24.12.0)(jiti@2.4.2)(lightningcss@1.31.1)(sass-embedded@1.98.0)(sass@1.98.0)(terser@5.31.6)(yaml@2.5.0)): dependencies: - '@vitest/expect': 4.0.18 - '@vitest/mocker': 4.0.18(vite@7.3.1(@types/node@24.12.0)(jiti@2.4.2)(lightningcss@1.31.1)(sass-embedded@1.98.0)(sass@1.98.0)(terser@5.31.6)(yaml@2.5.0)) - '@vitest/pretty-format': 4.0.18 - '@vitest/runner': 4.0.18 - '@vitest/snapshot': 4.0.18 - '@vitest/spy': 4.0.18 - '@vitest/utils': 4.0.18 - es-module-lexer: 1.7.0 + '@vitest/expect': 4.1.0 + '@vitest/mocker': 4.1.0(vite@7.3.1(@types/node@24.12.0)(jiti@2.4.2)(lightningcss@1.31.1)(sass-embedded@1.98.0)(sass@1.98.0)(terser@5.31.6)(yaml@2.5.0)) + '@vitest/pretty-format': 4.1.0 + '@vitest/runner': 4.1.0 + '@vitest/snapshot': 4.1.0 + '@vitest/spy': 4.1.0 + '@vitest/utils': 4.1.0 + es-module-lexer: 2.0.0 expect-type: 1.3.0 magic-string: 0.30.21 obug: 2.1.1 pathe: 2.0.3 picomatch: 4.0.3 - std-env: 3.10.0 + std-env: 4.0.0 tinybench: 2.9.0 tinyexec: 1.0.2 tinyglobby: 0.2.15 @@ -13568,20 +13581,10 @@ snapshots: why-is-node-running: 2.3.0 optionalDependencies: '@types/node': 24.12.0 - happy-dom: 20.8.3 + happy-dom: 20.8.4 jsdom: 27.4.0 transitivePeerDependencies: - - jiti - - less - - lightningcss - msw - - sass - - sass-embedded - - stylus - - sugarss - - terser - - tsx - - yaml vscode-uri@3.0.8: {} From 88a011aadce8543b73d1c68a2bd636bee4d99f96 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Sun, 15 Mar 2026 01:38:18 +0000 Subject: [PATCH 061/142] chore(deps): update dependency caniuse-lite to v1.0.30001779 --- frontend/package.json | 2 +- frontend/pnpm-lock.yaml | 14 +++++++------- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/frontend/package.json b/frontend/package.json index 632a56e6c..53a99cc0d 100644 --- a/frontend/package.json +++ b/frontend/package.json @@ -125,7 +125,7 @@ "@vueuse/shared": "14.2.1", "autoprefixer": "10.4.27", "browserslist": "4.28.1", - "caniuse-lite": "1.0.30001778", + "caniuse-lite": "1.0.30001779", "csstype": "3.2.3", "esbuild": "0.27.4", "eslint": "9.39.4", diff --git a/frontend/pnpm-lock.yaml b/frontend/pnpm-lock.yaml index 3339f98c3..8e731b139 100644 --- a/frontend/pnpm-lock.yaml +++ b/frontend/pnpm-lock.yaml @@ -232,8 +232,8 @@ importers: specifier: 4.28.1 version: 4.28.1 caniuse-lite: - specifier: 1.0.30001778 - version: 1.0.30001778 + specifier: 1.0.30001779 + version: 1.0.30001779 csstype: specifier: 3.2.3 version: 3.2.3 @@ -3283,8 +3283,8 @@ packages: resolution: {integrity: sha512-8WB3Jcas3swSvjIeA2yvCJ+Miyz5l1ZmB6HFb9R1317dt9LCQoswg/BGrmAmkWVEszSrrg4RwmO46qIm2OEnSA==} engines: {node: '>=16'} - caniuse-lite@1.0.30001778: - resolution: {integrity: sha512-PN7uxFL+ExFJO61aVmP1aIEG4i9whQd4eoSCebav62UwDyp5OHh06zN4jqKSMePVgxHifCw1QJxdRkA1Pisekg==} + caniuse-lite@1.0.30001779: + resolution: {integrity: sha512-U5og2PN7V4DMgF50YPNtnZJGWVLFjjsN3zb6uMT5VGYIewieDj1upwfuVNXf4Kor+89c3iCRJnSzMD5LmTvsfA==} capture-website@4.2.0: resolution: {integrity: sha512-EmkSn36CXTC8tUsS6aNmvvsdpfVTYYkuRp7U5bV9gcJwcDbqqA5c0Op/iskYPKtDdOkuVp61mjn/LLywX0h7cw==} @@ -9822,7 +9822,7 @@ snapshots: autoprefixer@10.4.27(postcss@8.5.8): dependencies: browserslist: 4.28.1 - caniuse-lite: 1.0.30001778 + caniuse-lite: 1.0.30001779 fraction.js: 5.3.4 picocolors: 1.1.1 postcss: 8.5.8 @@ -9941,7 +9941,7 @@ snapshots: browserslist@4.28.1: dependencies: baseline-browser-mapping: 2.9.4 - caniuse-lite: 1.0.30001778 + caniuse-lite: 1.0.30001779 electron-to-chromium: 1.5.266 node-releases: 2.0.27 update-browserslist-db: 1.2.2(browserslist@4.28.1) @@ -10003,7 +10003,7 @@ snapshots: camelcase@8.0.0: {} - caniuse-lite@1.0.30001778: {} + caniuse-lite@1.0.30001779: {} capture-website@4.2.0(typescript@5.9.3): dependencies: From e20af6df40cc866f30fd3f651f09c91fd32bea5d Mon Sep 17 00:00:00 2001 From: kolaente Date: Tue, 17 Mar 2026 09:45:25 +0100 Subject: [PATCH 062/142] fix(deps): override flatted to 3.4.1 to fix unbounded recursion DoS Adds pnpm override for flatted to resolve GHSA-25h7-pfq9-p65f. --- frontend/package.json | 3 ++- frontend/pnpm-lock.yaml | 11 ++++++----- 2 files changed, 8 insertions(+), 6 deletions(-) diff --git a/frontend/package.json b/frontend/package.json index 53a99cc0d..7afb17590 100644 --- a/frontend/package.json +++ b/frontend/package.json @@ -168,7 +168,8 @@ "minimatch": "^10.2.3", "rollup": "$rollup", "basic-ftp": "5.2.0", - "serialize-javascript": "^7.0.3" + "serialize-javascript": "^7.0.3", + "flatted": "^3.4.1" } } } diff --git a/frontend/pnpm-lock.yaml b/frontend/pnpm-lock.yaml index 8e731b139..65e32b007 100644 --- a/frontend/pnpm-lock.yaml +++ b/frontend/pnpm-lock.yaml @@ -9,6 +9,7 @@ overrides: rollup: 4.59.0 basic-ftp: 5.2.0 serialize-javascript: ^7.0.3 + flatted: ^3.4.1 importers: @@ -3976,8 +3977,8 @@ packages: flatpickr@4.6.13: resolution: {integrity: sha512-97PMG/aywoYpB4IvbvUJi0RQi8vearvU0oov1WW3k0WZPBMrTQVqekSX5CjSG/M4Q3i6A/0FKXC7RyAoAUUSPw==} - flatted@3.3.3: - resolution: {integrity: sha512-GX+ysw4PBCz0PzosHDepZGANEuFCMLrnRTiEy9McGjmkCQYwRq4A/X786G/fjM/+OjsWSU1ZrY5qyARZmO/uwg==} + flatted@3.4.1: + resolution: {integrity: sha512-IxfVbRFVlV8V/yRaGzk0UVIcsKKHMSfYw66T/u4nTwlWteQePsxe//LjudR1AMX4tZW3WFCh3Zqa/sjlqpbURQ==} flexsearch@0.8.212: resolution: {integrity: sha512-wSyJr1GUWoOOIISRu+X2IXiOcVfg9qqBRyCPRUdLMIGJqPzMo+jMRlvE83t14v1j0dRMEaBbER/adQjp6Du2pw==} @@ -10769,18 +10770,18 @@ snapshots: flat-cache@4.0.1: dependencies: - flatted: 3.3.3 + flatted: 3.4.1 keyv: 4.5.4 flat-cache@6.1.20: dependencies: cacheable: 2.3.2 - flatted: 3.3.3 + flatted: 3.4.1 hookified: 1.15.1 flatpickr@4.6.13: {} - flatted@3.3.3: {} + flatted@3.4.1: {} flexsearch@0.8.212: {} From dc581fdcbe2c638a466dd944443be77833ddaf08 Mon Sep 17 00:00:00 2001 From: kolaente Date: Tue, 17 Mar 2026 09:45:29 +0100 Subject: [PATCH 063/142] fix(deps): update tar override to 7.5.11 to fix symlink path traversal Updates pnpm override for tar to resolve GHSA-9ppj-qmqm-q256. --- desktop/package.json | 2 +- desktop/pnpm-lock.yaml | 38 ++++++++++++++++++++++---------------- 2 files changed, 23 insertions(+), 17 deletions(-) diff --git a/desktop/package.json b/desktop/package.json index 7c7533f36..e47450b5f 100644 --- a/desktop/package.json +++ b/desktop/package.json @@ -65,7 +65,7 @@ ], "overrides": { "minimatch": "^10.2.3", - "tar": "^7.5.10", + "tar": "^7.5.11", "@tootallnate/once": "^3.0.1" } } diff --git a/desktop/pnpm-lock.yaml b/desktop/pnpm-lock.yaml index 03f53144c..aff895791 100644 --- a/desktop/pnpm-lock.yaml +++ b/desktop/pnpm-lock.yaml @@ -6,7 +6,7 @@ settings: overrides: minimatch: ^10.2.3 - tar: ^7.5.10 + tar: ^7.5.11 '@tootallnate/once': ^3.0.1 importers: @@ -1040,6 +1040,10 @@ packages: resolution: {integrity: sha512-qOOzS1cBTWYF4BH8fVePDBOO9iptMnGUEZwNc/cMWnTV2nVLZ7VoNWEPHkYczZA0pdoA7dl6e7FL659nX9S2aw==} engines: {node: '>=16 || 14 >=14.17'} + minipass@7.1.3: + resolution: {integrity: sha512-tEBHqDnIoM/1rXME1zgka9g6Q2lcoCkxHLuc7ODJ5BxbP5d4c2Z5cGgtXAku59200Cx7diuHTOYfSBD8n6mm8A==} + engines: {node: '>=16 || 14 >=14.17'} + minizlib@3.1.0: resolution: {integrity: sha512-KZxYo1BUkWD2TVFLr0MQoM8vUUigWD3LlD83a/75BqC+4qE0Hb1Vo5v1FgcfaNXvfXzr+5EhQ6ing/CaBijTlw==} engines: {node: '>= 18'} @@ -1263,8 +1267,8 @@ packages: resolution: {integrity: sha512-1n3r/tGXO6b6VXMdFT54SHzT9ytu9yr7TaELowdYpMqY/Ao7EnlQGmAQ1+RatX7Tkkdm6hONI2owqNx2aZj5Sw==} engines: {node: '>=11.0.0'} - sax@1.5.0: - resolution: {integrity: sha512-21IYA3Q5cQf089Z6tgaUTr7lDAyzoTPx5HRtbhsME8Udispad8dC/+sziTNugOEx54ilvatQ9YCzl4KQLPcRHA==} + sax@1.6.0: + resolution: {integrity: sha512-6R3J5M4AcbtLUdZmRv2SygeVaM7IhrLXu9BmnOGmmACak8fiUtOsYNWUS4uK7upbmHIBbLBeFeI//477BKLBzA==} engines: {node: '>=11.0.0'} semver-compare@1.0.0: @@ -1405,8 +1409,8 @@ packages: resolution: {integrity: sha512-ujeqbceABgwMZxEJnk2HDY2DlnUZ+9oEcb1KzTVfYHio0UE6dG71n60d8D2I4qNvleWrrXpmjpt7vZeF1LnMZQ==} engines: {node: '>=6'} - tar@7.5.10: - resolution: {integrity: sha512-8mOPs1//5q/rlkNSPcCegA6hiHJYDmSLEI8aMH/CdSQJNWztHC9WHNam5zdQlfpTwB9Xp7IBEsHfV5LKMJGVAw==} + tar@7.5.11: + resolution: {integrity: sha512-ChjMH33/KetonMTAtpYdgUFr0tbz69Fp2v7zWxQfYZX4g5ZN2nOBXm1R2xyA+lMIKrLKIoKAwFj93jE/avX9cQ==} engines: {node: '>=18'} temp-file@3.4.0: @@ -1647,7 +1651,7 @@ snapshots: ora: 5.4.1 read-binary-file-arch: 1.0.6 semver: 7.7.4 - tar: 7.5.10 + tar: 7.5.11 yargs: 17.7.2 transitivePeerDependencies: - supports-color @@ -1687,7 +1691,7 @@ snapshots: '@isaacs/fs-minipass@4.0.1': dependencies: - minipass: 7.1.2 + minipass: 7.1.3 '@malept/cross-spawn-promise@1.1.1': dependencies: @@ -1847,7 +1851,7 @@ snapshots: read-config-file: 6.3.2 sanitize-filename: 1.6.3 semver: 7.7.4 - tar: 7.5.10 + tar: 7.5.11 temp-file: 3.4.0 transitivePeerDependencies: - supports-color @@ -1888,7 +1892,7 @@ snapshots: proper-lockfile: 4.1.2 resedit: 1.7.2 semver: 7.7.4 - tar: 7.5.10 + tar: 7.5.11 temp-file: 3.4.0 tiny-async-pool: 1.3.0 which: 5.0.0 @@ -1998,7 +2002,7 @@ snapshots: builder-util-runtime@9.2.4: dependencies: debug: 4.4.3 - sax: 1.5.0 + sax: 1.6.0 transitivePeerDependencies: - supports-color @@ -2065,7 +2069,7 @@ snapshots: minipass-pipeline: 1.2.4 p-map: 7.0.4 ssri: 12.0.0 - tar: 7.5.10 + tar: 7.5.11 unique-filename: 4.0.0 cacheable-lookup@5.0.4: {} @@ -2876,9 +2880,11 @@ snapshots: minipass@7.1.2: {} + minipass@7.1.3: {} + minizlib@3.1.0: dependencies: - minipass: 7.1.2 + minipass: 7.1.3 ms@2.1.3: {} @@ -2904,7 +2910,7 @@ snapshots: nopt: 8.1.0 proc-log: 5.0.0 semver: 7.7.4 - tar: 7.5.10 + tar: 7.5.11 tinyglobby: 0.2.15 which: 5.0.0 transitivePeerDependencies: @@ -3114,7 +3120,7 @@ snapshots: sax@1.4.4: {} - sax@1.5.0: {} + sax@1.6.0: {} semver-compare@1.0.0: optional: true @@ -3285,11 +3291,11 @@ snapshots: inherits: 2.0.4 readable-stream: 3.6.2 - tar@7.5.10: + tar@7.5.11: dependencies: '@isaacs/fs-minipass': 4.0.1 chownr: 3.0.0 - minipass: 7.1.2 + minipass: 7.1.3 minizlib: 3.1.0 yallist: 5.0.0 From 176588bf1df78324f5697ca3b07368bf01903c97 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Tue, 17 Mar 2026 08:46:52 +0000 Subject: [PATCH 064/142] chore(deps): update dev-dependencies --- frontend/package.json | 6 +- frontend/pnpm-lock.yaml | 164 ++++++++++++++++++++-------------------- 2 files changed, 85 insertions(+), 85 deletions(-) diff --git a/frontend/package.json b/frontend/package.json index 7afb17590..0bf673dc2 100644 --- a/frontend/package.json +++ b/frontend/package.json @@ -116,8 +116,8 @@ "@types/is-touch-device": "1.0.3", "@types/node": "24.12.0", "@types/sortablejs": "1.15.9", - "@typescript-eslint/eslint-plugin": "8.57.0", - "@typescript-eslint/parser": "8.57.0", + "@typescript-eslint/eslint-plugin": "8.57.1", + "@typescript-eslint/parser": "8.57.1", "@vitejs/plugin-vue": "6.0.5", "@vue/eslint-config-typescript": "14.7.0", "@vue/test-utils": "2.4.6", @@ -125,7 +125,7 @@ "@vueuse/shared": "14.2.1", "autoprefixer": "10.4.27", "browserslist": "4.28.1", - "caniuse-lite": "1.0.30001779", + "caniuse-lite": "1.0.30001780", "csstype": "3.2.3", "esbuild": "0.27.4", "eslint": "9.39.4", diff --git a/frontend/pnpm-lock.yaml b/frontend/pnpm-lock.yaml index 65e32b007..be108efa5 100644 --- a/frontend/pnpm-lock.yaml +++ b/frontend/pnpm-lock.yaml @@ -206,17 +206,17 @@ importers: specifier: 1.15.9 version: 1.15.9 '@typescript-eslint/eslint-plugin': - specifier: 8.57.0 - version: 8.57.0(@typescript-eslint/parser@8.57.0(eslint@9.39.4(jiti@2.4.2))(typescript@5.9.3))(eslint@9.39.4(jiti@2.4.2))(typescript@5.9.3) + specifier: 8.57.1 + version: 8.57.1(@typescript-eslint/parser@8.57.1(eslint@9.39.4(jiti@2.4.2))(typescript@5.9.3))(eslint@9.39.4(jiti@2.4.2))(typescript@5.9.3) '@typescript-eslint/parser': - specifier: 8.57.0 - version: 8.57.0(eslint@9.39.4(jiti@2.4.2))(typescript@5.9.3) + specifier: 8.57.1 + version: 8.57.1(eslint@9.39.4(jiti@2.4.2))(typescript@5.9.3) '@vitejs/plugin-vue': specifier: 6.0.5 version: 6.0.5(vite@7.3.1(@types/node@24.12.0)(jiti@2.4.2)(lightningcss@1.31.1)(sass-embedded@1.98.0)(sass@1.98.0)(terser@5.31.6)(yaml@2.5.0))(vue@3.5.27(typescript@5.9.3)) '@vue/eslint-config-typescript': specifier: 14.7.0 - version: 14.7.0(eslint-plugin-vue@10.8.0(@typescript-eslint/parser@8.57.0(eslint@9.39.4(jiti@2.4.2))(typescript@5.9.3))(eslint@9.39.4(jiti@2.4.2))(vue-eslint-parser@10.4.0(eslint@9.39.4(jiti@2.4.2))))(eslint@9.39.4(jiti@2.4.2))(typescript@5.9.3) + version: 14.7.0(eslint-plugin-vue@10.8.0(@typescript-eslint/parser@8.57.1(eslint@9.39.4(jiti@2.4.2))(typescript@5.9.3))(eslint@9.39.4(jiti@2.4.2))(vue-eslint-parser@10.4.0(eslint@9.39.4(jiti@2.4.2))))(eslint@9.39.4(jiti@2.4.2))(typescript@5.9.3) '@vue/test-utils': specifier: 2.4.6 version: 2.4.6 @@ -233,8 +233,8 @@ importers: specifier: 4.28.1 version: 4.28.1 caniuse-lite: - specifier: 1.0.30001779 - version: 1.0.30001779 + specifier: 1.0.30001780 + version: 1.0.30001780 csstype: specifier: 3.2.3 version: 3.2.3 @@ -249,7 +249,7 @@ importers: version: 1.5.0(eslint@9.39.4(jiti@2.4.2)) eslint-plugin-vue: specifier: 10.8.0 - version: 10.8.0(@typescript-eslint/parser@8.57.0(eslint@9.39.4(jiti@2.4.2))(typescript@5.9.3))(eslint@9.39.4(jiti@2.4.2))(vue-eslint-parser@10.4.0(eslint@9.39.4(jiti@2.4.2))) + version: 10.8.0(@typescript-eslint/parser@8.57.1(eslint@9.39.4(jiti@2.4.2))(typescript@5.9.3))(eslint@9.39.4(jiti@2.4.2))(vue-eslint-parser@10.4.0(eslint@9.39.4(jiti@2.4.2))) happy-dom: specifier: 20.8.4 version: 20.8.4 @@ -2687,11 +2687,11 @@ packages: eslint: ^8.57.0 || ^9.0.0 || ^10.0.0 typescript: '>=4.8.4 <6.0.0' - '@typescript-eslint/eslint-plugin@8.57.0': - resolution: {integrity: sha512-qeu4rTHR3/IaFORbD16gmjq9+rEs9fGKdX0kF6BKSfi+gCuG3RCKLlSBYzn/bGsY9Tj7KE/DAQStbp8AHJGHEQ==} + '@typescript-eslint/eslint-plugin@8.57.1': + resolution: {integrity: sha512-Gn3aqnvNl4NGc6x3/Bqk1AOn0thyTU9bqDRhiRnUWezgvr2OnhYCWCgC8zXXRVqBsIL1pSDt7T9nJUe0oM0kDQ==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} peerDependencies: - '@typescript-eslint/parser': ^8.57.0 + '@typescript-eslint/parser': ^8.57.1 eslint: ^8.57.0 || ^9.0.0 || ^10.0.0 typescript: '>=4.8.4 <6.0.0' @@ -2702,8 +2702,8 @@ packages: eslint: ^8.57.0 || ^9.0.0 || ^10.0.0 typescript: '>=4.8.4 <6.0.0' - '@typescript-eslint/parser@8.57.0': - resolution: {integrity: sha512-XZzOmihLIr8AD1b9hL9ccNMzEMWt/dE2u7NyTY9jJG6YNiNthaD5XtUHVF2uCXZ15ng+z2hT3MVuxnUYhq6k1g==} + '@typescript-eslint/parser@8.57.1': + resolution: {integrity: sha512-k4eNDan0EIMTT/dUKc/g+rsJ6wcHYhNPdY19VoX/EOtaAG8DLtKCykhrUnuHPYvinn5jhAPgD2Qw9hXBwrahsw==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} peerDependencies: eslint: ^8.57.0 || ^9.0.0 || ^10.0.0 @@ -2721,8 +2721,8 @@ packages: peerDependencies: typescript: '>=4.8.4 <6.0.0' - '@typescript-eslint/project-service@8.57.0': - resolution: {integrity: sha512-pR+dK0BlxCLxtWfaKQWtYr7MhKmzqZxuii+ZjuFlZlIGRZm22HnXFqa2eY+90MUz8/i80YJmzFGDUsi8dMOV5w==} + '@typescript-eslint/project-service@8.57.1': + resolution: {integrity: sha512-vx1F37BRO1OftsYlmG9xay1TqnjNVlqALymwWVuYTdo18XuKxtBpCj1QlzNIEHlvlB27osvXFWptYiEWsVdYsg==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} peerDependencies: typescript: '>=4.8.4 <6.0.0' @@ -2735,8 +2735,8 @@ packages: resolution: {integrity: sha512-7UiO/XwMHquH+ZzfVCfUNkIXlp/yQjjnlYUyYz7pfvlK3/EyyN6BK+emDmGNyQLBtLGaYrTAI6KOw8tFucWL2w==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} - '@typescript-eslint/scope-manager@8.57.0': - resolution: {integrity: sha512-nvExQqAHF01lUM66MskSaZulpPL5pgy5hI5RfrxviLgzZVffB5yYzw27uK/ft8QnKXI2X0LBrHJFr1TaZtAibw==} + '@typescript-eslint/scope-manager@8.57.1': + resolution: {integrity: sha512-hs/QcpCwlwT2L5S+3fT6gp0PabyGk4Q0Rv2doJXA0435/OpnSR3VRgvrp8Xdoc3UAYSg9cyUjTeFXZEPg/3OKg==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} '@typescript-eslint/tsconfig-utils@8.49.0': @@ -2751,14 +2751,14 @@ packages: peerDependencies: typescript: '>=4.8.4 <6.0.0' - '@typescript-eslint/tsconfig-utils@8.56.1': - resolution: {integrity: sha512-qOtCYzKEeyr3aR9f28mPJqBty7+DBqsdd63eO0yyDwc6vgThj2UjWfJIcsFeSucYydqcuudMOprZ+x1SpF3ZuQ==} + '@typescript-eslint/tsconfig-utils@8.57.0': + resolution: {integrity: sha512-LtXRihc5ytjJIQEH+xqjB0+YgsV4/tW35XKX3GTZHpWtcC8SPkT/d4tqdf1cKtesryHm2bgp6l555NYcT2NLvA==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} peerDependencies: typescript: '>=4.8.4 <6.0.0' - '@typescript-eslint/tsconfig-utils@8.57.0': - resolution: {integrity: sha512-LtXRihc5ytjJIQEH+xqjB0+YgsV4/tW35XKX3GTZHpWtcC8SPkT/d4tqdf1cKtesryHm2bgp6l555NYcT2NLvA==} + '@typescript-eslint/tsconfig-utils@8.57.1': + resolution: {integrity: sha512-0lgOZB8cl19fHO4eI46YUx2EceQqhgkPSuCGLlGi79L2jwYY1cxeYc1Nae8Aw1xjgW3PKVDLlr3YJ6Bxx8HkWg==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} peerDependencies: typescript: '>=4.8.4 <6.0.0' @@ -2770,8 +2770,8 @@ packages: eslint: ^8.57.0 || ^9.0.0 || ^10.0.0 typescript: '>=4.8.4 <6.0.0' - '@typescript-eslint/type-utils@8.57.0': - resolution: {integrity: sha512-yjgh7gmDcJ1+TcEg8x3uWQmn8ifvSupnPfjP21twPKrDP/pTHlEQgmKcitzF/rzPSmv7QjJ90vRpN4U+zoUjwQ==} + '@typescript-eslint/type-utils@8.57.1': + resolution: {integrity: sha512-+Bwwm0ScukFdyoJsh2u6pp4S9ktegF98pYUU0hkphOOqdMB+1sNQhIz8y5E9+4pOioZijrkfNO/HUJVAFFfPKA==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} peerDependencies: eslint: ^8.57.0 || ^9.0.0 || ^10.0.0 @@ -2785,14 +2785,14 @@ packages: resolution: {integrity: sha512-DBsLPs3GsWhX5HylbP9HNG15U0bnwut55Lx12bHB9MpXxQ+R5GC8MwQe+N1UFXxAeQDvEsEDY6ZYwX03K7Z6HQ==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} - '@typescript-eslint/types@8.56.1': - resolution: {integrity: sha512-dbMkdIUkIkchgGDIv7KLUpa0Mda4IYjo4IAMJUZ+3xNoUXxMsk9YtKpTHSChRS85o+H9ftm51gsK1dZReY9CVw==} - engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} - '@typescript-eslint/types@8.57.0': resolution: {integrity: sha512-dTLI8PEXhjUC7B9Kre+u0XznO696BhXcTlOn0/6kf1fHaQW8+VjJAVHJ3eTI14ZapTxdkOmc80HblPQLaEeJdg==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + '@typescript-eslint/types@8.57.1': + resolution: {integrity: sha512-S29BOBPJSFUiblEl6RzPPjJt6w25A6XsBqRVDt53tA/tlL8q7ceQNZHTjPeONt/3S7KRI4quk+yP9jK2WjBiPQ==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + '@typescript-eslint/typescript-estree@8.49.0': resolution: {integrity: sha512-jrLdRuAbPfPIdYNppHJ/D0wN+wwNfJ32YTAm10eJVsFmrVpXQnDWBn8niCSMlWjvml8jsce5E/O+86IQtTbJWA==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} @@ -2805,8 +2805,8 @@ packages: peerDependencies: typescript: '>=4.8.4 <6.0.0' - '@typescript-eslint/typescript-estree@8.57.0': - resolution: {integrity: sha512-m7faHcyVg0BT3VdYTlX8GdJEM7COexXxS6KqGopxdtkQRvBanK377QDHr4W/vIPAR+ah9+B/RclSW5ldVniO1Q==} + '@typescript-eslint/typescript-estree@8.57.1': + resolution: {integrity: sha512-ybe2hS9G6pXpqGtPli9Gx9quNV0TWLOmh58ADlmZe9DguLq0tiAKVjirSbtM1szG6+QH6rVXyU6GTLQbWnMY+g==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} peerDependencies: typescript: '>=4.8.4 <6.0.0' @@ -2818,8 +2818,8 @@ packages: eslint: ^8.57.0 || ^9.0.0 || ^10.0.0 typescript: '>=4.8.4 <6.0.0' - '@typescript-eslint/utils@8.57.0': - resolution: {integrity: sha512-5iIHvpD3CZe06riAsbNxxreP+MuYgVUsV0n4bwLH//VJmgtt54sQeY2GszntJ4BjYCpMzrfVh2SBnUQTtys2lQ==} + '@typescript-eslint/utils@8.57.1': + resolution: {integrity: sha512-XUNSJ/lEVFttPMMoDVA2r2bwrl8/oPx8cURtczkSEswY5T3AeLmCy+EKWQNdL4u0MmAHOjcWrqJp2cdvgjn8dQ==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} peerDependencies: eslint: ^8.57.0 || ^9.0.0 || ^10.0.0 @@ -2833,8 +2833,8 @@ packages: resolution: {integrity: sha512-q+SL+b+05Ud6LbEE35qe4A99P+htKTKVbyiNEe45eCbJFyh/HVK9QXwlrbz+Q4L8SOW4roxSVwXYj4DMBT7Ieg==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} - '@typescript-eslint/visitor-keys@8.57.0': - resolution: {integrity: sha512-zm6xx8UT/Xy2oSr2ZXD0pZo7Jx2XsCoID2IUh9YSTFRu7z+WdwYTRk6LhUftm1crwqbuoF6I8zAFeCMw0YjwDg==} + '@typescript-eslint/visitor-keys@8.57.1': + resolution: {integrity: sha512-YWnmJkXbofiz9KbnbbwuA2rpGkFPLbAIetcCNO6mJ8gdhdZ/v7WDXsoGFAJuM6ikUFKTlSQnjWnVO4ux+UzS6A==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} '@ungap/structured-clone@1.3.0': @@ -3284,8 +3284,8 @@ packages: resolution: {integrity: sha512-8WB3Jcas3swSvjIeA2yvCJ+Miyz5l1ZmB6HFb9R1317dt9LCQoswg/BGrmAmkWVEszSrrg4RwmO46qIm2OEnSA==} engines: {node: '>=16'} - caniuse-lite@1.0.30001779: - resolution: {integrity: sha512-U5og2PN7V4DMgF50YPNtnZJGWVLFjjsN3zb6uMT5VGYIewieDj1upwfuVNXf4Kor+89c3iCRJnSzMD5LmTvsfA==} + caniuse-lite@1.0.30001780: + resolution: {integrity: sha512-llngX0E7nQci5BPJDqoZSbuZ5Bcs9F5db7EtgfwBerX9XGtkkiO4NwfDDIRzHTTwcYC8vC7bmeUEPGrKlR/TkQ==} capture-website@4.2.0: resolution: {integrity: sha512-EmkSn36CXTC8tUsS6aNmvvsdpfVTYYkuRp7U5bV9gcJwcDbqqA5c0Op/iskYPKtDdOkuVp61mjn/LLywX0h7cw==} @@ -9272,14 +9272,14 @@ snapshots: transitivePeerDependencies: - supports-color - '@typescript-eslint/eslint-plugin@8.57.0(@typescript-eslint/parser@8.57.0(eslint@9.39.4(jiti@2.4.2))(typescript@5.9.3))(eslint@9.39.4(jiti@2.4.2))(typescript@5.9.3)': + '@typescript-eslint/eslint-plugin@8.57.1(@typescript-eslint/parser@8.57.1(eslint@9.39.4(jiti@2.4.2))(typescript@5.9.3))(eslint@9.39.4(jiti@2.4.2))(typescript@5.9.3)': dependencies: '@eslint-community/regexpp': 4.12.2 - '@typescript-eslint/parser': 8.57.0(eslint@9.39.4(jiti@2.4.2))(typescript@5.9.3) - '@typescript-eslint/scope-manager': 8.57.0 - '@typescript-eslint/type-utils': 8.57.0(eslint@9.39.4(jiti@2.4.2))(typescript@5.9.3) - '@typescript-eslint/utils': 8.57.0(eslint@9.39.4(jiti@2.4.2))(typescript@5.9.3) - '@typescript-eslint/visitor-keys': 8.57.0 + '@typescript-eslint/parser': 8.57.1(eslint@9.39.4(jiti@2.4.2))(typescript@5.9.3) + '@typescript-eslint/scope-manager': 8.57.1 + '@typescript-eslint/type-utils': 8.57.1(eslint@9.39.4(jiti@2.4.2))(typescript@5.9.3) + '@typescript-eslint/utils': 8.57.1(eslint@9.39.4(jiti@2.4.2))(typescript@5.9.3) + '@typescript-eslint/visitor-keys': 8.57.1 eslint: 9.39.4(jiti@2.4.2) ignore: 7.0.5 natural-compare: 1.4.0 @@ -9300,12 +9300,12 @@ snapshots: transitivePeerDependencies: - supports-color - '@typescript-eslint/parser@8.57.0(eslint@9.39.4(jiti@2.4.2))(typescript@5.9.3)': + '@typescript-eslint/parser@8.57.1(eslint@9.39.4(jiti@2.4.2))(typescript@5.9.3)': dependencies: - '@typescript-eslint/scope-manager': 8.57.0 - '@typescript-eslint/types': 8.57.0 - '@typescript-eslint/typescript-estree': 8.57.0(typescript@5.9.3) - '@typescript-eslint/visitor-keys': 8.57.0 + '@typescript-eslint/scope-manager': 8.57.1 + '@typescript-eslint/types': 8.57.1 + '@typescript-eslint/typescript-estree': 8.57.1(typescript@5.9.3) + '@typescript-eslint/visitor-keys': 8.57.1 debug: 4.4.3 eslint: 9.39.4(jiti@2.4.2) typescript: 5.9.3 @@ -9314,8 +9314,8 @@ snapshots: '@typescript-eslint/project-service@8.49.0(typescript@5.9.3)': dependencies: - '@typescript-eslint/tsconfig-utils': 8.56.1(typescript@5.9.3) - '@typescript-eslint/types': 8.56.1 + '@typescript-eslint/tsconfig-utils': 8.57.0(typescript@5.9.3) + '@typescript-eslint/types': 8.57.0 debug: 4.4.3 typescript: 5.9.3 transitivePeerDependencies: @@ -9323,17 +9323,17 @@ snapshots: '@typescript-eslint/project-service@8.56.0(typescript@5.9.3)': dependencies: - '@typescript-eslint/tsconfig-utils': 8.56.1(typescript@5.9.3) - '@typescript-eslint/types': 8.56.1 + '@typescript-eslint/tsconfig-utils': 8.57.0(typescript@5.9.3) + '@typescript-eslint/types': 8.57.0 debug: 4.4.3 typescript: 5.9.3 transitivePeerDependencies: - supports-color - '@typescript-eslint/project-service@8.57.0(typescript@5.9.3)': + '@typescript-eslint/project-service@8.57.1(typescript@5.9.3)': dependencies: - '@typescript-eslint/tsconfig-utils': 8.57.0(typescript@5.9.3) - '@typescript-eslint/types': 8.57.0 + '@typescript-eslint/tsconfig-utils': 8.57.1(typescript@5.9.3) + '@typescript-eslint/types': 8.57.1 debug: 4.4.3 typescript: 5.9.3 transitivePeerDependencies: @@ -9349,10 +9349,10 @@ snapshots: '@typescript-eslint/types': 8.56.0 '@typescript-eslint/visitor-keys': 8.56.0 - '@typescript-eslint/scope-manager@8.57.0': + '@typescript-eslint/scope-manager@8.57.1': dependencies: - '@typescript-eslint/types': 8.57.0 - '@typescript-eslint/visitor-keys': 8.57.0 + '@typescript-eslint/types': 8.57.1 + '@typescript-eslint/visitor-keys': 8.57.1 '@typescript-eslint/tsconfig-utils@8.49.0(typescript@5.9.3)': dependencies: @@ -9362,11 +9362,11 @@ snapshots: dependencies: typescript: 5.9.3 - '@typescript-eslint/tsconfig-utils@8.56.1(typescript@5.9.3)': + '@typescript-eslint/tsconfig-utils@8.57.0(typescript@5.9.3)': dependencies: typescript: 5.9.3 - '@typescript-eslint/tsconfig-utils@8.57.0(typescript@5.9.3)': + '@typescript-eslint/tsconfig-utils@8.57.1(typescript@5.9.3)': dependencies: typescript: 5.9.3 @@ -9382,11 +9382,11 @@ snapshots: transitivePeerDependencies: - supports-color - '@typescript-eslint/type-utils@8.57.0(eslint@9.39.4(jiti@2.4.2))(typescript@5.9.3)': + '@typescript-eslint/type-utils@8.57.1(eslint@9.39.4(jiti@2.4.2))(typescript@5.9.3)': dependencies: - '@typescript-eslint/types': 8.57.0 - '@typescript-eslint/typescript-estree': 8.57.0(typescript@5.9.3) - '@typescript-eslint/utils': 8.57.0(eslint@9.39.4(jiti@2.4.2))(typescript@5.9.3) + '@typescript-eslint/types': 8.57.1 + '@typescript-eslint/typescript-estree': 8.57.1(typescript@5.9.3) + '@typescript-eslint/utils': 8.57.1(eslint@9.39.4(jiti@2.4.2))(typescript@5.9.3) debug: 4.4.3 eslint: 9.39.4(jiti@2.4.2) ts-api-utils: 2.4.0(typescript@5.9.3) @@ -9398,10 +9398,10 @@ snapshots: '@typescript-eslint/types@8.56.0': {} - '@typescript-eslint/types@8.56.1': {} - '@typescript-eslint/types@8.57.0': {} + '@typescript-eslint/types@8.57.1': {} + '@typescript-eslint/typescript-estree@8.49.0(typescript@5.9.3)': dependencies: '@typescript-eslint/project-service': 8.49.0(typescript@5.9.3) @@ -9432,12 +9432,12 @@ snapshots: transitivePeerDependencies: - supports-color - '@typescript-eslint/typescript-estree@8.57.0(typescript@5.9.3)': + '@typescript-eslint/typescript-estree@8.57.1(typescript@5.9.3)': dependencies: - '@typescript-eslint/project-service': 8.57.0(typescript@5.9.3) - '@typescript-eslint/tsconfig-utils': 8.57.0(typescript@5.9.3) - '@typescript-eslint/types': 8.57.0 - '@typescript-eslint/visitor-keys': 8.57.0 + '@typescript-eslint/project-service': 8.57.1(typescript@5.9.3) + '@typescript-eslint/tsconfig-utils': 8.57.1(typescript@5.9.3) + '@typescript-eslint/types': 8.57.1 + '@typescript-eslint/visitor-keys': 8.57.1 debug: 4.4.3 minimatch: 10.2.4 semver: 7.7.3 @@ -9458,12 +9458,12 @@ snapshots: transitivePeerDependencies: - supports-color - '@typescript-eslint/utils@8.57.0(eslint@9.39.4(jiti@2.4.2))(typescript@5.9.3)': + '@typescript-eslint/utils@8.57.1(eslint@9.39.4(jiti@2.4.2))(typescript@5.9.3)': dependencies: '@eslint-community/eslint-utils': 4.9.1(eslint@9.39.4(jiti@2.4.2)) - '@typescript-eslint/scope-manager': 8.57.0 - '@typescript-eslint/types': 8.57.0 - '@typescript-eslint/typescript-estree': 8.57.0(typescript@5.9.3) + '@typescript-eslint/scope-manager': 8.57.1 + '@typescript-eslint/types': 8.57.1 + '@typescript-eslint/typescript-estree': 8.57.1(typescript@5.9.3) eslint: 9.39.4(jiti@2.4.2) typescript: 5.9.3 transitivePeerDependencies: @@ -9479,9 +9479,9 @@ snapshots: '@typescript-eslint/types': 8.56.0 eslint-visitor-keys: 5.0.0 - '@typescript-eslint/visitor-keys@8.57.0': + '@typescript-eslint/visitor-keys@8.57.1': dependencies: - '@typescript-eslint/types': 8.57.0 + '@typescript-eslint/types': 8.57.1 eslint-visitor-keys: 5.0.0 '@ungap/structured-clone@1.3.0': {} @@ -9640,11 +9640,11 @@ snapshots: '@vue/devtools-shared@8.1.0': {} - '@vue/eslint-config-typescript@14.7.0(eslint-plugin-vue@10.8.0(@typescript-eslint/parser@8.57.0(eslint@9.39.4(jiti@2.4.2))(typescript@5.9.3))(eslint@9.39.4(jiti@2.4.2))(vue-eslint-parser@10.4.0(eslint@9.39.4(jiti@2.4.2))))(eslint@9.39.4(jiti@2.4.2))(typescript@5.9.3)': + '@vue/eslint-config-typescript@14.7.0(eslint-plugin-vue@10.8.0(@typescript-eslint/parser@8.57.1(eslint@9.39.4(jiti@2.4.2))(typescript@5.9.3))(eslint@9.39.4(jiti@2.4.2))(vue-eslint-parser@10.4.0(eslint@9.39.4(jiti@2.4.2))))(eslint@9.39.4(jiti@2.4.2))(typescript@5.9.3)': dependencies: '@typescript-eslint/utils': 8.56.0(eslint@9.39.4(jiti@2.4.2))(typescript@5.9.3) eslint: 9.39.4(jiti@2.4.2) - eslint-plugin-vue: 10.8.0(@typescript-eslint/parser@8.57.0(eslint@9.39.4(jiti@2.4.2))(typescript@5.9.3))(eslint@9.39.4(jiti@2.4.2))(vue-eslint-parser@10.4.0(eslint@9.39.4(jiti@2.4.2))) + eslint-plugin-vue: 10.8.0(@typescript-eslint/parser@8.57.1(eslint@9.39.4(jiti@2.4.2))(typescript@5.9.3))(eslint@9.39.4(jiti@2.4.2))(vue-eslint-parser@10.4.0(eslint@9.39.4(jiti@2.4.2))) fast-glob: 3.3.3 typescript-eslint: 8.56.0(eslint@9.39.4(jiti@2.4.2))(typescript@5.9.3) vue-eslint-parser: 10.4.0(eslint@9.39.4(jiti@2.4.2)) @@ -9823,7 +9823,7 @@ snapshots: autoprefixer@10.4.27(postcss@8.5.8): dependencies: browserslist: 4.28.1 - caniuse-lite: 1.0.30001779 + caniuse-lite: 1.0.30001780 fraction.js: 5.3.4 picocolors: 1.1.1 postcss: 8.5.8 @@ -9942,7 +9942,7 @@ snapshots: browserslist@4.28.1: dependencies: baseline-browser-mapping: 2.9.4 - caniuse-lite: 1.0.30001779 + caniuse-lite: 1.0.30001780 electron-to-chromium: 1.5.266 node-releases: 2.0.27 update-browserslist-db: 1.2.2(browserslist@4.28.1) @@ -10004,7 +10004,7 @@ snapshots: camelcase@8.0.0: {} - caniuse-lite@1.0.30001779: {} + caniuse-lite@1.0.30001780: {} capture-website@4.2.0(typescript@5.9.3): dependencies: @@ -10571,7 +10571,7 @@ snapshots: module-replacements: 2.11.0 semver: 7.7.3 - eslint-plugin-vue@10.8.0(@typescript-eslint/parser@8.57.0(eslint@9.39.4(jiti@2.4.2))(typescript@5.9.3))(eslint@9.39.4(jiti@2.4.2))(vue-eslint-parser@10.4.0(eslint@9.39.4(jiti@2.4.2))): + eslint-plugin-vue@10.8.0(@typescript-eslint/parser@8.57.1(eslint@9.39.4(jiti@2.4.2))(typescript@5.9.3))(eslint@9.39.4(jiti@2.4.2))(vue-eslint-parser@10.4.0(eslint@9.39.4(jiti@2.4.2))): dependencies: '@eslint-community/eslint-utils': 4.9.1(eslint@9.39.4(jiti@2.4.2)) eslint: 9.39.4(jiti@2.4.2) @@ -10582,7 +10582,7 @@ snapshots: vue-eslint-parser: 10.4.0(eslint@9.39.4(jiti@2.4.2)) xml-name-validator: 4.0.0 optionalDependencies: - '@typescript-eslint/parser': 8.57.0(eslint@9.39.4(jiti@2.4.2))(typescript@5.9.3) + '@typescript-eslint/parser': 8.57.1(eslint@9.39.4(jiti@2.4.2))(typescript@5.9.3) eslint-scope@8.4.0: dependencies: From 650ceabd3cbdd08b8f9d5412879fa2404d9616ae Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Tue, 17 Mar 2026 12:55:28 +0000 Subject: [PATCH 065/142] chore(deps): update dependency vue-tsc to v3.2.6 --- frontend/package.json | 2 +- frontend/pnpm-lock.yaml | 18 +++++++++--------- 2 files changed, 10 insertions(+), 10 deletions(-) diff --git a/frontend/package.json b/frontend/package.json index 0bf673dc2..5a6a2a8bd 100644 --- a/frontend/package.json +++ b/frontend/package.json @@ -152,7 +152,7 @@ "vite-plugin-vue-devtools": "8.1.0", "vite-svg-loader": "5.1.1", "vitest": "4.1.0", - "vue-tsc": "3.2.5", + "vue-tsc": "3.2.6", "wait-on": "9.0.4", "workbox-cli": "7.4.0" }, diff --git a/frontend/pnpm-lock.yaml b/frontend/pnpm-lock.yaml index be108efa5..1a9b1738e 100644 --- a/frontend/pnpm-lock.yaml +++ b/frontend/pnpm-lock.yaml @@ -314,8 +314,8 @@ importers: specifier: 4.1.0 version: 4.1.0(@types/node@24.12.0)(happy-dom@20.8.4)(jsdom@27.4.0)(vite@7.3.1(@types/node@24.12.0)(jiti@2.4.2)(lightningcss@1.31.1)(sass-embedded@1.98.0)(sass@1.98.0)(terser@5.31.6)(yaml@2.5.0)) vue-tsc: - specifier: 3.2.5 - version: 3.2.5(typescript@5.9.3) + specifier: 3.2.6 + version: 3.2.6(typescript@5.9.3) wait-on: specifier: 9.0.4 version: 9.0.4 @@ -2947,8 +2947,8 @@ packages: typescript: optional: true - '@vue/language-core@3.2.5': - resolution: {integrity: sha512-d3OIxN/+KRedeM5wQ6H6NIpwS3P5gC9nmyaHgBk+rO6dIsjY+tOh4UlPpiZbAh3YtLdCGEX4M16RmsBqPmJV+g==} + '@vue/language-core@3.2.6': + resolution: {integrity: sha512-xYYYX3/aVup576tP/23sEUpgiEnujrENaoNRbaozC1/MA9I6EGFQRJb4xrt/MmUCAGlxTKL2RmT8JLTPqagCkg==} '@vue/reactivity@3.5.27': resolution: {integrity: sha512-vvorxn2KXfJ0nBEnj4GYshSgsyMNFnIQah/wczXlsNXt+ijhugmW+PpJ2cNPe4V6jpnBcs0MhCODKllWG+nvoQ==} @@ -6613,8 +6613,8 @@ packages: peerDependencies: vue: ^3.5.0 - vue-tsc@3.2.5: - resolution: {integrity: sha512-/htfTCMluQ+P2FISGAooul8kO4JMheOTCbCy4M6dYnYYjqLe3BExZudAua6MSIKSFYQtFOYAll7XobYwcpokGA==} + vue-tsc@3.2.6: + resolution: {integrity: sha512-gYW/kWI0XrwGzd0PKc7tVB/qpdeAkIZLNZb10/InizkQjHjnT8weZ/vBarZoj4kHKbUTZT/bAVgoOr8x4NsQ/Q==} hasBin: true peerDependencies: typescript: '>=5.0.0' @@ -9653,7 +9653,7 @@ snapshots: transitivePeerDependencies: - supports-color - '@vue/language-core@3.2.5': + '@vue/language-core@3.2.6': dependencies: '@volar/language-core': 2.4.28 '@vue/compiler-dom': 3.5.27 @@ -13635,10 +13635,10 @@ snapshots: '@vue/devtools-api': 6.6.4 vue: 3.5.27(typescript@5.9.3) - vue-tsc@3.2.5(typescript@5.9.3): + vue-tsc@3.2.6(typescript@5.9.3): dependencies: '@volar/typescript': 2.4.28 - '@vue/language-core': 3.2.5 + '@vue/language-core': 3.2.6 typescript: 5.9.3 vue@3.5.27(typescript@5.9.3): From 50eb68fb2b0ba2270b13e1a18a8ac1fe8adbcf21 Mon Sep 17 00:00:00 2001 From: kolaente Date: Tue, 17 Mar 2026 19:11:45 +0100 Subject: [PATCH 066/142] fix(menu): show all project menu items in sidebar dropdown The `simple` prop was introduced to hide some menu items (Views, Set Background, Archive) in the sidebar to prevent overflow. Since the Dropdown component now uses @floating-ui/dom with autoPlacement and shift middleware, overflow is handled automatically, making the prop unnecessary. --- .../src/components/home/ProjectsNavigationItem.vue | 1 - .../components/project/ProjectSettingsDropdown.vue | 11 +++-------- 2 files changed, 3 insertions(+), 9 deletions(-) diff --git a/frontend/src/components/home/ProjectsNavigationItem.vue b/frontend/src/components/home/ProjectsNavigationItem.vue index 9898e7d2b..4ab91f86f 100644 --- a/frontend/src/components/home/ProjectsNavigationItem.vue +++ b/frontend/src/components/home/ProjectsNavigationItem.vue @@ -64,7 +64,6 @@ v-if="project.maxPermission !== null && project.maxPermission > PERMISSIONS.READ" class="menu-list-dropdown" :project="project" - :simple="true" >