diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 3c9e28b8208..80c19be8c37 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -223,7 +223,7 @@ jobs: run: | mkdir -p .prebuilt-ui tar -xzvf .tarballs/prometheus-web-ui-*.tar.gz -C .prebuilt-ui - - uses: prometheus/promci/build@13941414d409d227afd67544e5d306827db5a1a2 # v0.8.5 + - uses: prometheus/promci/build@370e8c15dcec50043cbe66f2f34633d9efc0a190 # v0.9.0 with: checkout: false # Feed the restored UI assets into the crossbuild containers so make @@ -260,7 +260,7 @@ jobs: run: | mkdir -p .prebuilt-ui tar -xzvf .tarballs/prometheus-web-ui-*.tar.gz -C .prebuilt-ui - - uses: prometheus/promci/build@13941414d409d227afd67544e5d306827db5a1a2 # v0.8.5 + - uses: prometheus/promci/build@370e8c15dcec50043cbe66f2f34633d9efc0a190 # v0.9.0 with: checkout: false parallelism: 12 @@ -370,7 +370,7 @@ jobs: needs: [test_ui, test_go, test_go_more, test_go_oldest, test_windows, golangci, codeql, build_all] if: github.event_name == 'push' && github.event.ref == 'refs/heads/main' steps: - - uses: prometheus/promci/publish_main@13941414d409d227afd67544e5d306827db5a1a2 # v0.8.5 + - uses: prometheus/promci/publish_main@370e8c15dcec50043cbe66f2f34633d9efc0a190 # v0.9.0 with: docker_hub_login: ${{ secrets.docker_hub_login }} docker_hub_password: ${{ secrets.docker_hub_password }} @@ -389,7 +389,7 @@ jobs: || (github.event_name == 'push' && startsWith(github.ref, 'refs/tags/v3.')) steps: - - uses: prometheus/promci/publish_release@13941414d409d227afd67544e5d306827db5a1a2 # v0.8.5 + - uses: prometheus/promci/publish_release@370e8c15dcec50043cbe66f2f34633d9efc0a190 # v0.9.0 with: docker_hub_login: ${{ secrets.docker_hub_login }} docker_hub_password: ${{ secrets.docker_hub_password }} @@ -411,7 +411,7 @@ jobs: with: persist-credentials: false - name: Install nodejs - uses: actions/setup-node@48b55a011bda9f5d6aeb4c2d9c7362e8dae4041e # v6.4.0 + uses: actions/setup-node@249970729cb0ef3589644e2896645e5dc5ba9c38 # v6.5.0 with: node-version-file: "web/ui/.nvmrc" registry-url: "https://registry.npmjs.org" diff --git a/.github/workflows/stale.yml b/.github/workflows/stale.yml index 5df426b0967..25a0ad0b4dd 100644 --- a/.github/workflows/stale.yml +++ b/.github/workflows/stale.yml @@ -14,7 +14,7 @@ jobs: if: github.repository_owner == 'prometheus' || github.repository_owner == 'prometheus-community' # Don't run this workflow on forks. runs-on: ubuntu-latest steps: - - uses: actions/stale@eb5cf3af3ac0a1aa4c9c45633dd1ae542a27a899 # v10.3.0 + - uses: actions/stale@1e223db275d687790206a7acac4d1a11bd6fe629 # v10.4.0 with: repo-token: ${{ secrets.GITHUB_TOKEN }} # opt out of defaults to avoid marking issues as stale and closing them diff --git a/Makefile b/Makefile index 51f21e6a852..fb92ce87bc1 100644 --- a/Makefile +++ b/Makefile @@ -80,8 +80,12 @@ ui-build-module: cd $(UI_PATH) && pnpm run build:module .PHONY: ui-test -ui-test: +ui-test: ui-build-module cd $(UI_PATH) && CI=true pnpm run test + # The old React app has been separated from the npm workspaces setup to avoid + # issues with conflicting dependencies. This is a temporary solution until the + # new Mantine-based UI is fully integrated and the old app can be removed. + cd $(UI_PATH)/react-app && CI=true pnpm run test .PHONY: ui-lint ui-lint: @@ -172,7 +176,7 @@ install-goyacc: ifeq ($(GO_ONLY),1) test: common-test check-go-mod-version else -test: check-generated-parser common-test check-node-version ui-build-module ui-test ui-lint check-go-mod-version +test: check-generated-parser common-test check-node-version ui-test ui-lint check-go-mod-version endif .PHONY: tarball @@ -222,8 +226,8 @@ update-all-go-deps: update-go-deps .PHONY: update-go-deps-in-dir update-go-deps-in-dir: @echo ">> updating Go dependencies in ./$(DIR)/" + # GOTOOLCHAIN prevents go get from pulling deps that require a newer Go version. @cd ./$(DIR) && for m in $$($(GO) list -mod=readonly -m -f '{{ if and (not .Indirect) (not .Main)}}{{.Path}}{{end}}' all); do \ - # Prevent go get from pulling deps that require a newer Go version. GOTOOLCHAIN=go$$($(GO) mod edit -json | jq -r .Go) $(GO) get $$m; \ done @cd ./$(DIR) && $(GO) mod tidy diff --git a/Makefile.common b/Makefile.common index b336657fb39..c028133f052 100644 --- a/Makefile.common +++ b/Makefile.common @@ -165,8 +165,8 @@ common-deps: .PHONY: update-go-deps update-go-deps: @echo ">> updating Go dependencies" + # GOTOOLCHAIN prevents go get from pulling deps that require a newer Go version. @for m in $$($(GO) list -mod=readonly -m -f '{{ if and (not .Indirect) (not .Main)}}{{.Path}}{{end}}' all); do \ - # Prevent go get from pulling deps that require a newer Go version. GOTOOLCHAIN=go$$($(GO) mod edit -json | jq -r .Go) $(GO) get $$m; \ done $(GO) mod tidy diff --git a/cmd/prometheus/features_test.go b/cmd/prometheus/features_test.go index 5907c87247c..d5e97ce611a 100644 --- a/cmd/prometheus/features_test.go +++ b/cmd/prometheus/features_test.go @@ -23,7 +23,6 @@ import ( "os" "path/filepath" "testing" - "time" "github.com/stretchr/testify/require" @@ -53,15 +52,7 @@ func TestFeaturesAPI(t *testing.T) { baseURL := fmt.Sprintf("http://127.0.0.1:%d", port) - // Wait for Prometheus to be ready. - require.Eventually(t, func() bool { - resp, err := http.Get(baseURL + "/-/ready") - if err != nil { - return false - } - defer resp.Body.Close() - return resp.StatusCode == http.StatusOK - }, 10*time.Second, 100*time.Millisecond, "Prometheus didn't become ready in time") + waitForPrometheusReady(t, port) // Fetch features from the API. resp, err := http.Get(baseURL + "/api/v1/features") diff --git a/cmd/prometheus/main.go b/cmd/prometheus/main.go index 6e6c61d0f35..4ad2ede8628 100644 --- a/cmd/prometheus/main.go +++ b/cmd/prometheus/main.go @@ -84,6 +84,7 @@ import ( "github.com/prometheus/prometheus/util/documentcli" "github.com/prometheus/prometheus/util/features" "github.com/prometheus/prometheus/util/logging" + "github.com/prometheus/prometheus/util/memorylimiter" "github.com/prometheus/prometheus/util/notifications" prom_runtime "github.com/prometheus/prometheus/util/runtime" "github.com/prometheus/prometheus/web" @@ -217,6 +218,7 @@ type flagConfig struct { enablePerStepStats bool enableConcurrentRuleEval bool useStartTimestamps bool + enableMemoryLimiter bool prometheusURL string corsRegexString string @@ -345,6 +347,9 @@ func (c *flagConfig) setFeatureListOptions(logger *slog.Logger) error { case "search-api": c.web.EnableSearch = true logger.Info("Experimental search API enabled.") + case "memory-limiter": + c.enableMemoryLimiter = true + logger.Info("Experimental memory limiter is enabled.") default: logger.Warn("Unknown option for --enable-feature", "option", o) } @@ -378,6 +383,7 @@ func main() { collectors.NewGoCollector( collectors.WithGoCollectorRuntimeMetrics( collectors.MetricsGC, + collectors.MetricsMemory, collectors.MetricsScheduler, collectors.GoRuntimeMetricsRule{Matcher: goregexp.MustCompile(`^/sync/mutex/wait/total:seconds$`)}, ), @@ -645,7 +651,7 @@ func main() { a.Flag("scrape.discovery-reload-interval", "Interval used by scrape manager to throttle target groups updates."). Hidden().Default("5s").SetValue(&cfg.scrape.DiscoveryReloadInterval) - a.Flag("enable-feature", "Comma separated feature names to enable. Valid options: concurrent-rule-eval, created-timestamp-zero-ingestion, delayed-compaction, exemplar-storage, extra-scrape-metrics, histograms-st-encoding, memory-snapshot-on-shutdown, metadata-wal-records, old-ui, otlp-deltatocumulative, otlp-native-delta-ingestion, promql-binop-fill-modifiers, promql-delayed-name-removal, promql-experimental-functions, promql-extended-range-selectors, promql-per-step-stats, search-api, st-storage, st-synthesis, type-and-unit-labels, use-start-timestamps, use-uncached-io, xor2-encoding. See https://prometheus.io/docs/prometheus/latest/feature_flags/ for more details."). + a.Flag("enable-feature", "Comma separated feature names to enable. Valid options: concurrent-rule-eval, created-timestamp-zero-ingestion, delayed-compaction, exemplar-storage, extra-scrape-metrics, histograms-st-encoding, memory-limiter, memory-snapshot-on-shutdown, metadata-wal-records, old-ui, otlp-deltatocumulative, otlp-native-delta-ingestion, promql-binop-fill-modifiers, promql-delayed-name-removal, promql-experimental-functions, promql-extended-range-selectors, promql-per-step-stats, search-api, st-storage, st-synthesis, type-and-unit-labels, use-start-timestamps, use-uncached-io, xor2-encoding. See https://prometheus.io/docs/prometheus/latest/feature_flags/ for more details."). StringsVar(&cfg.featureList) a.Flag("agent", "Run Prometheus in 'Agent mode'.").BoolVar(&agentMode) @@ -969,6 +975,18 @@ func main() { os.Exit(1) } + var memoryLimiter memorylimiter.MemoryLimiter + if cfg.enableMemoryLimiter { + ml, err := memorylimiter.NewManager(&cfgFile.Runtime.MemoryLimiter, logger.With("component", "memory limiter"), prometheus.DefaultRegisterer) + if err != nil { + logger.Error("failed to create memory limiter", "err", err) + os.Exit(1) + } + memoryLimiter = ml + cfg.scrape.MemoryLimiter = ml + cfg.web.MemoryLimiter = ml + } + scrapeManager, err := scrape.NewManager( &cfg.scrape, logger.With("component", "scrape manager"), @@ -1037,6 +1055,7 @@ func main() { }, FeatureRegistry: features.DefaultRegistry, Parser: promqlParser, + MemoryLimiter: memoryLimiter, }) } @@ -1201,6 +1220,14 @@ func main() { }, { name: "tracing", reloader: tracingManager.ApplyConfig, + }, { + name: "memory_limiter", + reloader: func(cfg *config.Config) error { + if memoryLimiter != nil { + return memoryLimiter.ApplyConfig(&cfg.Runtime.MemoryLimiter) + } + return nil + }, }, } @@ -1294,6 +1321,21 @@ func main() { }, ) } + if memoryLimiter != nil { + ctxML, cancelML := context.WithCancel(context.Background()) + g.Add( + func() error { + memoryLimiter.Start(ctxML) + <-ctxML.Done() + return nil + }, + func(error) { + logger.Info("Stopping memory limiter...") + cancelML() + memoryLimiter.Stop() + }, + ) + } if !agentMode { // Rule manager. g.Add( diff --git a/cmd/prometheus/main_test.go b/cmd/prometheus/main_test.go index 29cb0713528..42e0ddeb52e 100644 --- a/cmd/prometheus/main_test.go +++ b/cmd/prometheus/main_test.go @@ -178,14 +178,7 @@ storage: ) require.NoError(t, prom.Start()) - require.Eventually(t, func() bool { - r, err := http.Get(fmt.Sprintf("http://127.0.0.1:%d/metrics", port)) - if err != nil { - return false - } - defer r.Body.Close() - return r.StatusCode == http.StatusOK - }, startupTime, 100*time.Millisecond) + waitForPrometheusReady(t, port) require.DirExists(t, storagePath) } @@ -704,9 +697,6 @@ func TestModeSpecificFlags(t *testing.T) { } func TestDocumentation(t *testing.T) { - if runtime.GOOS == "windows" { - t.SkipNow() - } t.Parallel() ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second) @@ -719,12 +709,17 @@ func TestDocumentation(t *testing.T) { require.NoError(t, cmd.Run(), "failed to generate CLI documentation via --write-documentation") - generatedContent := strings.ReplaceAll(stdout.String(), filepath.Base(promPath), strings.TrimSuffix(filepath.Base(promPath), ".test")) + appTitle := strings.TrimSuffix(filepath.Base(promPath), ".test") + if runtime.GOOS == "windows" { + appTitle = strings.TrimSuffix(appTitle, ".test.exe") + } + + generatedContent := strings.ReplaceAll(stdout.String(), filepath.Base(promPath), appTitle) expectedContent, err := os.ReadFile(filepath.Join("..", "..", "docs", "command-line", "prometheus.md")) require.NoError(t, err) - require.Equal(t, string(expectedContent), generatedContent, "Generated content does not match documentation. Hint: run `make cli-documentation`.") + require.Equal(t, strings.ReplaceAll(string(expectedContent), "\r\n", "\n"), generatedContent, "Generated content does not match documentation. Hint: run `make cli-documentation`.") } func TestRwProtoMsgFlagParser(t *testing.T) { @@ -902,26 +897,24 @@ global: fmt.Sprintf("--storage.tsdb.path=%s", tmpDir), "--web.enable-lifecycle", ) - // Inject GOGC when set. - prom.Env = os.Environ() + // Inject GOGC when set, and drop any inherited one otherwise, so + // that the environment the test runs in cannot influence the cases + // expecting the default or the configured value. + prom.Env = slices.DeleteFunc(os.Environ(), func(kv string) bool { + return strings.HasPrefix(kv, "GOGC=") + }) if tc.gogcEnvVar != "" { prom.Env = append(prom.Env, fmt.Sprintf("GOGC=%s", tc.gogcEnvVar)) } require.NoError(t, prom.Start()) + // Wait for the initial configuration to be applied: /metrics is + // already served before that happens. + waitForPrometheusReady(t, port) + ensureGOGCValue := func(val float64) { - var ( - r *http.Response - err error - ) - // Wait for the /metrics endpoint to be ready. - require.Eventually(t, func() bool { - r, err = http.Get(fmt.Sprintf("http://127.0.0.1:%d/metrics", port)) - if err != nil { - return false - } - return r.StatusCode == http.StatusOK - }, 5*time.Second, 50*time.Millisecond) + r, err := http.Get(fmt.Sprintf("http://127.0.0.1:%d/metrics", port)) + require.NoError(t, err) defer r.Body.Close() // Check the final GOGC that's set, consider go_gc_gogc_percent from /metrics as source of truth. @@ -1216,9 +1209,6 @@ remote_write: // TestFeatureFlagsDocumented ensures the --enable-feature help text in main.go // and the documented flags in docs/feature_flags.md list the same set of flags. func TestFeatureFlagsDocumented(t *testing.T) { - if runtime.GOOS == "windows" { - t.SkipNow() - } h, err := os.ReadFile(filepath.Join("..", "..", "cmd", "prometheus", "main.go")) require.NoError(t, err) m := regexp.MustCompile(`a\.Flag\("enable-feature", "Comma separated feature names to enable. Valid options: (.+?)\.`).FindSubmatch(h) @@ -1230,6 +1220,10 @@ func TestFeatureFlagsDocumented(t *testing.T) { require.NotEmpty(t, helpFlags) d, err := os.ReadFile(filepath.Join("..", "..", "docs", "feature_flags.md")) + if runtime.GOOS == "windows" { + d = bytes.ReplaceAll(d, []byte("\r\n"), []byte("\n")) + } + require.NoError(t, err) var docFlags []string for _, dm := range regexp.MustCompile("(?m)^`--enable-feature=(.+)`$").FindAllSubmatch(d, -1) { diff --git a/cmd/prometheus/reload_test.go b/cmd/prometheus/reload_test.go index c3b6452afa7..4666981821a 100644 --- a/cmd/prometheus/reload_test.go +++ b/cmd/prometheus/reload_test.go @@ -123,14 +123,7 @@ func runTestSteps(t *testing.T, steps []struct { require.NoError(t, prom.Start()) baseURL := "http://localhost:" + strconv.Itoa(port) - require.Eventually(t, func() bool { - resp, err := http.Get(baseURL + "/-/ready") - if err != nil { - return false - } - defer resp.Body.Close() - return resp.StatusCode == http.StatusOK - }, 5*time.Second, 100*time.Millisecond, "Prometheus didn't become ready in time") + waitForPrometheusReady(t, port) for i, step := range steps { t.Logf("Step %d", i) @@ -241,3 +234,25 @@ func prometheusCommandWithLogging(t testing.TB, configFilePath string, port int, args = append(args, extraArgs...) return commandWithLogging(t, nil, promPath, args...) } + +// readyTimeout is how long we wait for a Prometheus process to become ready. It +// is generous on purpose: CI runs these tests with the race detector, which +// slows down both the test binary and the Prometheus processes it spawns in +// parallel. +const readyTimeout = 30 * time.Second + +// waitForPrometheusReady waits until the Prometheus instance listening on port +// reports itself as ready, which means it has opened its storage and applied +// its initial configuration. +func waitForPrometheusReady(t testing.TB, port int) { + t.Helper() + + require.Eventually(t, func() bool { + resp, err := http.Get("http://127.0.0.1:" + strconv.Itoa(port) + "/-/ready") + if err != nil { + return false + } + defer resp.Body.Close() + return resp.StatusCode == http.StatusOK + }, readyTimeout, 100*time.Millisecond, "Prometheus didn't become ready in time") +} diff --git a/compliance/go.mod b/compliance/go.mod index 145bc039236..3839380fe4e 100644 --- a/compliance/go.mod +++ b/compliance/go.mod @@ -1,6 +1,6 @@ module compliance -go 1.25.8 +go 1.25.10 require github.com/prometheus/compliance/remotewrite v0.0.0-20260223092825-818283e1171e diff --git a/config/config.go b/config/config.go index 7777a02ba8d..9df07a2d6fa 100644 --- a/config/config.go +++ b/config/config.go @@ -193,7 +193,24 @@ var ( DefaultRuntimeConfig = RuntimeConfig{ // Go runtime tuning. - GoGC: getGoGC(), + GoGC: getGoGC(), + MemoryLimiter: DefaultMemoryLimiterConfig, + } + + DefaultMemoryLimiterConfig = MemoryLimiterConfig{ + CheckInterval: model.Duration(100 * time.Millisecond), + SoftLimitRatio: 0.70, + HardLimitRatio: 0.85, + Enforcement: DefaultMemoryLimiterEnforcement, + } + + DefaultMemoryLimiterEnforcement = MemoryLimiterEnforcement{ + RejectRemoteRead: true, + RejectFederation: true, + FailScrapes: true, + RejectOTLP: true, + RejectRemoteWrite: true, + PauseRecordingRules: true, } // DefaultScrapeConfig is the default scrape configuration. Users of this @@ -735,25 +752,78 @@ type RuntimeConfig struct { // The Go garbage collection target percentage. GoGC int `yaml:"gogc,omitempty"` - // Below are guidelines for adding a new field: - // - // For config that shouldn't change after startup, you might want to use - // flags https://prometheus.io/docs/prometheus/latest/command-line/prometheus/. - // - // Consider when the new field is first applied: at the very beginning of instance - // startup, after the TSDB is loaded etc. See https://github.com/prometheus/prometheus/pull/16491 - // for an example. - // - // Provide a test covering various scenarios: empty config file, empty or incomplete runtime - // config block, precedence over other inputs (e.g., env vars, if applicable) etc. - // See TestRuntimeGOGCConfig (or https://github.com/prometheus/prometheus/pull/15238). - // The test should also verify behavior on reloads, since this config should be - // adjustable at runtime. + MemoryLimiter MemoryLimiterConfig `yaml:"memory_limiter,omitempty"` +} + +// MemoryLimiterConfig configures the global memory limiter. +type MemoryLimiterConfig struct { + CheckInterval model.Duration `yaml:"check_interval,omitempty"` + SoftLimitRatio float64 `yaml:"soft_limit_ratio,omitempty"` + HardLimitRatio float64 `yaml:"hard_limit_ratio,omitempty"` + Enforcement MemoryLimiterEnforcement `yaml:"enforcement,omitempty"` +} + +// MemoryLimiterEnforcement configures which mitigations are enabled. +type MemoryLimiterEnforcement struct { + // Soft Limit mitigations. + RejectRemoteRead bool `yaml:"reject_remote_read,omitempty"` + RejectFederation bool `yaml:"reject_federation,omitempty"` + + // Hard Limit mitigations. + FailScrapes bool `yaml:"fail_scrapes,omitempty"` + RejectOTLP bool `yaml:"reject_otlp,omitempty"` + RejectRemoteWrite bool `yaml:"reject_remote_write,omitempty"` + PauseRecordingRules bool `yaml:"pause_recording_rules,omitempty"` +} + +// isZero returns true iff the memory limiter config is the zero value. +func (c *MemoryLimiterConfig) isZero() bool { + return c.CheckInterval == 0 && c.SoftLimitRatio == 0 && c.HardLimitRatio == 0 && c.Enforcement.isZero() +} + +// isZero returns true iff the enforcement config is the zero value. +func (e *MemoryLimiterEnforcement) isZero() bool { + return !e.RejectRemoteRead && !e.RejectFederation && + !e.FailScrapes && !e.RejectOTLP && !e.RejectRemoteWrite && !e.PauseRecordingRules +} + +// Validate validates the memory limiter configuration. +func (c *MemoryLimiterConfig) Validate() error { + if c.CheckInterval <= 0 { + return errors.New("memory_limiter check_interval must be greater than 0") + } + if c.SoftLimitRatio <= 0 || c.SoftLimitRatio > 1.0 { + return fmt.Errorf("memory_limiter soft_limit_ratio must be between 0 and 1 (inclusive), got %f", c.SoftLimitRatio) + } + if c.HardLimitRatio <= 0 || c.HardLimitRatio > 1.0 { + return fmt.Errorf("memory_limiter hard_limit_ratio must be between 0 and 1 (inclusive), got %f", c.HardLimitRatio) + } + if c.SoftLimitRatio > c.HardLimitRatio { + return fmt.Errorf("memory_limiter soft_limit_ratio (%f) cannot be greater than hard_limit_ratio (%f)", c.SoftLimitRatio, c.HardLimitRatio) + } + return nil +} + +// UnmarshalYAML implements the yaml.Unmarshaler interface. +func (c *RuntimeConfig) UnmarshalYAML(unmarshal func(any) error) error { + *c = DefaultRuntimeConfig + type plain RuntimeConfig + return unmarshal((*plain)(c)) +} + +// UnmarshalYAML implements the yaml.Unmarshaler interface. +func (c *MemoryLimiterConfig) UnmarshalYAML(unmarshal func(any) error) error { + *c = DefaultMemoryLimiterConfig + type plain MemoryLimiterConfig + if err := unmarshal((*plain)(c)); err != nil { + return err + } + return c.Validate() } // isZero returns true iff the global config is the zero value. func (c *RuntimeConfig) isZero() bool { - return c.GoGC == 0 + return c.GoGC == 0 && c.MemoryLimiter.isZero() } type ScrapeConfigs struct { diff --git a/config/config_test.go b/config/config_test.go index b18972c00fa..d991d75937b 100644 --- a/config/config_test.go +++ b/config/config_test.go @@ -84,16 +84,17 @@ const ( globLabelNameLengthLimit = 200 globLabelValueLengthLimit = 200 globalGoGC = 42 - globScrapeFailureLogFile = "testdata/fail.log" ) +var globScrapeFailureLogFile = filepath.FromSlash("testdata/fail.log") + var expectedConf = &Config{ loaded: true, GlobalConfig: GlobalConfig{ ScrapeInterval: model.Duration(15 * time.Second), ScrapeTimeout: DefaultGlobalConfig.ScrapeTimeout, EvaluationInterval: model.Duration(30 * time.Second), - QueryLogFile: "testdata/query.log", + QueryLogFile: filepath.FromSlash("testdata/query.log"), ScrapeFailureLogFile: globScrapeFailureLogFile, ExternalLabels: labels.FromStrings("foo", "bar", "monitor", "codelab"), @@ -112,7 +113,8 @@ var expectedConf = &Config{ }, Runtime: RuntimeConfig{ - GoGC: globalGoGC, + GoGC: globalGoGC, + MemoryLimiter: DefaultMemoryLimiterConfig, }, RuleFiles: []string{ @@ -229,7 +231,7 @@ var expectedConf = &Config{ LabelValueLengthLimit: globLabelValueLengthLimit, ScrapeProtocols: DefaultScrapeProtocols, ScrapeFallbackProtocol: PrometheusText0_0_4, - ScrapeFailureLogFile: "testdata/fail_prom.log", + ScrapeFailureLogFile: filepath.FromSlash("testdata/fail_prom.log"), MetricNameValidationScheme: DefaultGlobalConfig.MetricNameValidationScheme, MetricNameEscapingScheme: DefaultGlobalConfig.MetricNameEscapingScheme, ScrapeNativeHistograms: boolPtr(false), @@ -263,11 +265,15 @@ var expectedConf = &Config{ ServiceDiscoveryConfigs: discovery.Configs{ &file.SDConfig{ - Files: []string{"testdata/foo/*.slow.json", "testdata/foo/*.slow.yml", "testdata/single/file.yml"}, + Files: []string{ + filepath.FromSlash("testdata/foo/*.slow.json"), + filepath.FromSlash("testdata/foo/*.slow.yml"), + filepath.FromSlash("testdata/single/file.yml"), + }, RefreshInterval: model.Duration(10 * time.Minute), }, &file.SDConfig{ - Files: []string{"testdata/bar/*.yaml"}, + Files: []string{filepath.FromSlash("testdata/bar/*.yaml")}, RefreshInterval: model.Duration(5 * time.Minute), }, discovery.StaticConfig{ @@ -1110,8 +1116,8 @@ var expectedConf = &Config{ RefreshInterval: model.Duration(60 * time.Second), Version: 1, TLSConfig: config.TLSConfig{ - CertFile: "testdata/valid_cert_file", - KeyFile: "testdata/valid_key_file", + CertFile: filepath.FromSlash("testdata/valid_cert_file"), + KeyFile: filepath.FromSlash("testdata/valid_key_file"), }, }, }, @@ -1266,7 +1272,7 @@ var expectedConf = &Config{ Tenancy: "ocid1.tenancy.oc1..tenancy001", User: "ocid1.user.oc1..user001", Fingerprint: "aa:bb:cc:dd:ee:ff", - KeyFile: "testdata/valid_key_file", + KeyFile: filepath.FromSlash("testdata/valid_key_file"), KeyPassphrase: "mysecret", Compartments: []string{"ocid1.compartment.oc1..comp001"}, Port: 9100, @@ -1309,9 +1315,9 @@ var expectedConf = &Config{ Availability: "public", RefreshInterval: model.Duration(60 * time.Second), TLSConfig: config.TLSConfig{ - CAFile: "testdata/valid_ca_file", - CertFile: "testdata/valid_cert_file", - KeyFile: "testdata/valid_key_file", + CAFile: filepath.FromSlash("testdata/valid_ca_file"), + CertFile: filepath.FromSlash("testdata/valid_cert_file"), + KeyFile: filepath.FromSlash("testdata/valid_key_file"), }, }, }, @@ -1353,9 +1359,9 @@ var expectedConf = &Config{ FollowRedirects: true, EnableHTTP2: true, TLSConfig: config.TLSConfig{ - CAFile: "testdata/valid_ca_file", - CertFile: "testdata/valid_cert_file", - KeyFile: "testdata/valid_key_file", + CAFile: filepath.FromSlash("testdata/valid_ca_file"), + CertFile: filepath.FromSlash("testdata/valid_cert_file"), + KeyFile: filepath.FromSlash("testdata/valid_key_file"), }, }, }, @@ -1837,8 +1843,8 @@ var expectedConf = &Config{ Timeout: model.Duration(5 * time.Second), Headers: map[string]string{"foo": "bar"}, TLSConfig: config.TLSConfig{ - CertFile: "testdata/valid_cert_file", - KeyFile: "testdata/valid_key_file", + CertFile: filepath.FromSlash("testdata/valid_cert_file"), + KeyFile: filepath.FromSlash("testdata/valid_key_file"), InsecureSkipVerify: true, }, }, @@ -3583,3 +3589,83 @@ func TestGetScrapeConfigs_Loaded(t *testing.T) { require.NoError(t, err) }) } + +func TestMemoryLimiterConfigValidation(t *testing.T) { + tests := []struct { + name string + yamlStr string + expectError bool + }{ + { + name: "valid config", + yamlStr: ` +check_interval: 100ms +soft_limit_ratio: 0.8 +hard_limit_ratio: 0.9 +enforcement: + fail_scrapes: true +`, + expectError: false, + }, + { + name: "invalid check_interval", + yamlStr: ` +check_interval: -1s +soft_limit_ratio: 0.8 +hard_limit_ratio: 0.9 +`, + expectError: true, + }, + { + name: "invalid soft_limit_ratio low", + yamlStr: ` +check_interval: 100ms +soft_limit_ratio: 0.0 +hard_limit_ratio: 0.9 +`, + expectError: true, + }, + { + name: "invalid hard_limit_ratio high", + yamlStr: ` +check_interval: 100ms +soft_limit_ratio: 0.8 +hard_limit_ratio: 1.5 +`, + expectError: true, + }, + { + name: "soft limit ratio greater than hard limit ratio", + yamlStr: ` +check_interval: 100ms +soft_limit_ratio: 0.9 +hard_limit_ratio: 0.8 +`, + expectError: true, + }, + { + name: "zero initialized check_interval", + yamlStr: ` +check_interval: 0s +soft_limit_ratio: 0.8 +hard_limit_ratio: 0.9 +`, + expectError: true, + }, + } + + for _, tc := range tests { + t.Run(tc.name, func(t *testing.T) { + var cfg MemoryLimiterConfig + err := yaml.UnmarshalStrict([]byte(tc.yamlStr), &cfg) + if err == nil { + err = cfg.Validate() + } + if tc.expectError { + require.Error(t, err) + } else { + require.NoError(t, err) + } + }) + } +} diff --git a/config/config_windows_test.go b/config/config_windows_test.go index e7627f562a2..691dcb015d4 100644 --- a/config/config_windows_test.go +++ b/config/config_windows_test.go @@ -20,6 +20,7 @@ var ruleFilesExpectedConf = &Config{ GlobalConfig: DefaultGlobalConfig, Runtime: DefaultRuntimeConfig, + OTLPConfig: DefaultOTLPConfig, StorageConfig: StorageConfig{TSDBConfig: &TSDBConfig{Retention: &TSDBRetentionConfig{}}}, RuleFiles: []string{ "testdata\\first.rules", diff --git a/discovery/aws/ecs.go b/discovery/aws/ecs.go index 84accaebb8c..7ea33974d6f 100644 --- a/discovery/aws/ecs.go +++ b/discovery/aws/ecs.go @@ -876,6 +876,11 @@ func (d *ECSDiscovery) refresh(ctx context.Context) ([]*targetgroup.Group, error networkMode = "awsvpc" var eniID string for _, detail := range eniAttachment.Details { + // Name and Value are both optional in the ECS API. + // Skip the entry rather than dereferencing nil. + if detail.Name == nil || detail.Value == nil { + continue + } switch *detail.Name { case "privateIPv4Address": ipAddress = *detail.Value @@ -906,10 +911,10 @@ func (d *ECSDiscovery) refresh(ctx context.Context) ([]*targetgroup.Group, error ec2InstancePrivateIP = info.privateIP ec2InstancePublicIP = info.publicIP } else { - d.logger.Debug("EC2 instance info not found", "instance", ec2InstanceID, "task", *task.TaskArn) + d.logger.Debug("EC2 instance info not found", "instance", ec2InstanceID, "task", aws.ToString(task.TaskArn)) } } else { - d.logger.Debug("Container instance not found in map", "arn", *task.ContainerInstanceArn, "task", *task.TaskArn) + d.logger.Debug("Container instance not found in map", "arn", *task.ContainerInstanceArn, "task", aws.ToString(task.TaskArn)) } } @@ -932,20 +937,42 @@ func (d *ECSDiscovery) refresh(ctx context.Context) ([]*targetgroup.Group, error return } + // Only IPAddress, Region, LaunchType, HealthStatus and + // NetworkMode are always available here: the first is + // checked above and the rest are not pointers. Every other + // field is optional in the ECS API, so emit its label only + // when present rather than dereferencing nil. labels := model.LabelSet{ - ecsLabelClusterARN: model.LabelValue(*cluster.ClusterArn), - ecsLabelCluster: model.LabelValue(*cluster.ClusterName), - ecsLabelTaskGroup: model.LabelValue(*task.Group), - ecsLabelTaskARN: model.LabelValue(*task.TaskArn), - ecsLabelTaskDefinition: model.LabelValue(*task.TaskDefinitionArn), - ecsLabelIPAddress: model.LabelValue(ipAddress), - ecsLabelRegion: model.LabelValue(d.region), - ecsLabelLaunchType: model.LabelValue(task.LaunchType), - ecsLabelAvailabilityZone: model.LabelValue(*task.AvailabilityZone), - ecsLabelDesiredStatus: model.LabelValue(*task.DesiredStatus), - ecsLabelLastStatus: model.LabelValue(*task.LastStatus), - ecsLabelHealthStatus: model.LabelValue(task.HealthStatus), - ecsLabelNetworkMode: model.LabelValue(networkMode), + ecsLabelIPAddress: model.LabelValue(ipAddress), + ecsLabelRegion: model.LabelValue(d.region), + ecsLabelLaunchType: model.LabelValue(task.LaunchType), + ecsLabelHealthStatus: model.LabelValue(task.HealthStatus), + ecsLabelNetworkMode: model.LabelValue(networkMode), + } + + if cluster.ClusterArn != nil { + labels[ecsLabelClusterARN] = model.LabelValue(*cluster.ClusterArn) + } + if cluster.ClusterName != nil { + labels[ecsLabelCluster] = model.LabelValue(*cluster.ClusterName) + } + if task.Group != nil { + labels[ecsLabelTaskGroup] = model.LabelValue(*task.Group) + } + if task.TaskArn != nil { + labels[ecsLabelTaskARN] = model.LabelValue(*task.TaskArn) + } + if task.TaskDefinitionArn != nil { + labels[ecsLabelTaskDefinition] = model.LabelValue(*task.TaskDefinitionArn) + } + if task.AvailabilityZone != nil { + labels[ecsLabelAvailabilityZone] = model.LabelValue(*task.AvailabilityZone) + } + if task.DesiredStatus != nil { + labels[ecsLabelDesiredStatus] = model.LabelValue(*task.DesiredStatus) + } + if task.LastStatus != nil { + labels[ecsLabelLastStatus] = model.LabelValue(*task.LastStatus) } // Add subnet ID when available (awsvpc mode from ENI, bridge/host from EC2 instance) @@ -990,10 +1017,10 @@ func (d *ECSDiscovery) refresh(ctx context.Context) ([]*targetgroup.Group, error } // If this task belongs to a service, add service information and tags. - if serviceName, isServiceTask := strings.CutPrefix(*task.Group, "service:"); isServiceTask { + if serviceName, isServiceTask := strings.CutPrefix(aws.ToString(task.Group), "service:"); isServiceTask { service, ok := services[serviceName] if !ok { - d.logger.Debug("Service not found for task", "task", *task.TaskArn, "service", serviceName) + d.logger.Debug("Service not found for task", "task", aws.ToString(task.TaskArn), "service", serviceName) } if service.ServiceName != nil { labels[ecsLabelService] = model.LabelValue(*service.ServiceName) diff --git a/discovery/aws/ecs_test.go b/discovery/aws/ecs_test.go index 2fe4815fa0b..793e8ee64f3 100644 --- a/discovery/aws/ecs_test.go +++ b/discovery/aws/ecs_test.go @@ -22,6 +22,7 @@ import ( "github.com/aws/aws-sdk-go-v2/service/ecs" ecsTypes "github.com/aws/aws-sdk-go-v2/service/ecs/types" "github.com/prometheus/common/model" + "github.com/prometheus/common/promslog" "github.com/stretchr/testify/require" "github.com/prometheus/prometheus/discovery/targetgroup" @@ -1497,6 +1498,67 @@ func TestECSDiscoveryRefresh(t *testing.T) { }, }, }, + { + // Every pointer blanked here is optional in the ECS API and was + // dereferenced without a nil check. A task that has not been placed + // yet has no AvailabilityZone, and an attachment detail is a + // KeyValuePair whose Name and Value are both optional, so a single + // absent field panicked the whole refresh instead of degrading the + // one target. + name: "TaskWithNilOptionalFields", + ecsData: &ecsDataStore{ + region: "us-west-2", + clusters: []ecsTypes.Cluster{ + { + ClusterName: strptr("nil-cluster"), + ClusterArn: strptr("arn:aws:ecs:us-west-2:123456789012:cluster/nil-cluster"), + Status: strptr("ACTIVE"), + }, + }, + tasks: []ecsTypes.Task{ + { + TaskArn: strptr("arn:aws:ecs:us-west-2:123456789012:task/nil-cluster/task-nil"), + ClusterArn: strptr("arn:aws:ecs:us-west-2:123456789012:cluster/nil-cluster"), + TaskDefinitionArn: strptr("arn:aws:ecs:us-west-2:123456789012:task-definition/nil-task:1"), + LaunchType: ecsTypes.LaunchTypeFargate, + // Group, LastStatus, DesiredStatus and AvailabilityZone + // are all absent. + Attachments: []ecsTypes.Attachment{ + { + Type: strptr("ElasticNetworkInterface"), + Details: []ecsTypes.KeyValuePair{ + // A detail with no Name at all. + {}, + // A known key whose Value is absent. + {Name: strptr("subnetId")}, + {Name: strptr("privateIPv4Address"), Value: strptr("10.0.4.10")}, + }, + }, + }, + }, + }, + }, + expected: []*targetgroup.Group{ + { + Source: "us-west-2", + Targets: []model.LabelSet{ + { + model.AddressLabel: model.LabelValue("10.0.4.10:80"), + "__meta_ecs_cluster": model.LabelValue("nil-cluster"), + "__meta_ecs_cluster_arn": model.LabelValue("arn:aws:ecs:us-west-2:123456789012:cluster/nil-cluster"), + "__meta_ecs_task_arn": model.LabelValue("arn:aws:ecs:us-west-2:123456789012:task/nil-cluster/task-nil"), + "__meta_ecs_task_definition": model.LabelValue( + "arn:aws:ecs:us-west-2:123456789012:task-definition/nil-task:1"), + "__meta_ecs_region": model.LabelValue("us-west-2"), + "__meta_ecs_ip_address": model.LabelValue("10.0.4.10"), + "__meta_ecs_launch_type": model.LabelValue("FARGATE"), + "__meta_ecs_health_status": model.LabelValue(""), + "__meta_ecs_network_mode": model.LabelValue("awsvpc"), + }, + }, + }, + }, + }, } for _, tt := range tests { @@ -1513,6 +1575,10 @@ func TestECSDiscoveryRefresh(t *testing.T) { RequestConcurrency: 1, }, region: tt.ecsData.region, + // NewECSDiscovery substitutes a no-op logger when none is + // supplied; construct the same thing here so the debug paths + // are exercised rather than panicking on a nil logger. + logger: promslog.NewNopLogger(), } groups, err := d.refresh(ctx) diff --git a/discovery/aws/elasticache.go b/discovery/aws/elasticache.go index 7aa1090cb01..cef8d35ba12 100644 --- a/discovery/aws/elasticache.go +++ b/discovery/aws/elasticache.go @@ -519,7 +519,7 @@ func (d *ElasticacheDiscovery) refresh(ctx context.Context) ([]*targetgroup.Grou var clusters []string clustersMu := sync.Mutex{} - serverlessCacheIDs, cacheClusterIDs := splitCacheDeploymentOptions(d.cfg.Clusters) + serverlessCacheIDs, cacheClusterIDs := splitCacheDeploymentOptions(d.cfg.Clusters, d.logger) clusterErrg, clusterCtx := errgroup.WithContext(ctx) clusterErrg.Go(func() error { @@ -594,13 +594,14 @@ func (d *ElasticacheDiscovery) refresh(ctx context.Context) ([]*targetgroup.Grou // splitCacheTypes takes a list of cache ARNs and splits them into serverless cache IDs and cache cluster IDs based on their format. // Serverless caches are in the format arn:aws:elasticache:::serverlesscache: // Cache clusters are in the format arn:aws:elasticache:::replicationgroup:. -func splitCacheDeploymentOptions(caches []string) (serverlessCacheIDs, cacheClusterIDs []string) { +func splitCacheDeploymentOptions(caches []string, logger *slog.Logger) (serverlessCacheIDs, cacheClusterIDs []string) { for _, cacheARN := range caches { if cacheARN == "" { continue } parts := strings.Split(cacheARN, ":") - if len(parts) < 6 { + if len(parts) < 7 { + logger.Warn("Skipping invalid ElastiCache ARN", "arn", cacheARN) continue } resourceType := parts[5] diff --git a/discovery/aws/elasticache_test.go b/discovery/aws/elasticache_test.go index 646c5d2a81d..434a77540c2 100644 --- a/discovery/aws/elasticache_test.go +++ b/discovery/aws/elasticache_test.go @@ -22,6 +22,7 @@ import ( "github.com/aws/aws-sdk-go-v2/service/elasticache" "github.com/aws/aws-sdk-go-v2/service/elasticache/types" "github.com/prometheus/common/model" + "github.com/prometheus/common/promslog" "github.com/stretchr/testify/require" "github.com/prometheus/prometheus/discovery/targetgroup" @@ -582,6 +583,7 @@ func TestSplitCacheDeploymentOptions(t *testing.T) { caches: []string{ "not-an-arn", "arn:aws:elasticache:us-east-1", + "arn:aws:elasticache:us-east-1:123456789012:serverlesscache", "", }, expectedServerlessCacheIDs: nil, @@ -611,7 +613,7 @@ func TestSplitCacheDeploymentOptions(t *testing.T) { for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { - serverlessCacheIDs, cacheClusterIDs := splitCacheDeploymentOptions(tt.caches) + serverlessCacheIDs, cacheClusterIDs := splitCacheDeploymentOptions(tt.caches, promslog.NewNopLogger()) require.Equal(t, tt.expectedServerlessCacheIDs, serverlessCacheIDs, "serverless cache IDs mismatch") require.Equal(t, tt.expectedCacheClusterIDs, cacheClusterIDs, "cache cluster IDs mismatch") diff --git a/discovery/aws/lightsail.go b/discovery/aws/lightsail.go index 2021e07dbcc..eea8f308564 100644 --- a/discovery/aws/lightsail.go +++ b/discovery/aws/lightsail.go @@ -258,15 +258,31 @@ func (d *LightsailDiscovery) refresh(ctx context.Context) ([]*targetgroup.Group, continue } + // Every field below is optional in the Lightsail API. Omit the label + // when the field is absent rather than dereferencing a nil pointer, + // which would panic and take down the whole Prometheus process. labels := model.LabelSet{ - lightsailLabelAZ: model.LabelValue(*inst.Location.AvailabilityZone), - lightsailLabelBlueprintID: model.LabelValue(*inst.BlueprintId), - lightsailLabelBundleID: model.LabelValue(*inst.BundleId), - lightsailLabelInstanceName: model.LabelValue(*inst.Name), - lightsailLabelInstanceState: model.LabelValue(*inst.State.Name), - lightsailLabelInstanceSupportCode: model.LabelValue(*inst.SupportCode), - lightsailLabelPrivateIP: model.LabelValue(*inst.PrivateIpAddress), - lightsailLabelRegion: model.LabelValue(d.region), + lightsailLabelPrivateIP: model.LabelValue(*inst.PrivateIpAddress), + lightsailLabelRegion: model.LabelValue(d.region), + } + + if inst.Location != nil && inst.Location.AvailabilityZone != nil { + labels[lightsailLabelAZ] = model.LabelValue(*inst.Location.AvailabilityZone) + } + if inst.BlueprintId != nil { + labels[lightsailLabelBlueprintID] = model.LabelValue(*inst.BlueprintId) + } + if inst.BundleId != nil { + labels[lightsailLabelBundleID] = model.LabelValue(*inst.BundleId) + } + if inst.Name != nil { + labels[lightsailLabelInstanceName] = model.LabelValue(*inst.Name) + } + if inst.State != nil && inst.State.Name != nil { + labels[lightsailLabelInstanceState] = model.LabelValue(*inst.State.Name) + } + if inst.SupportCode != nil { + labels[lightsailLabelInstanceSupportCode] = model.LabelValue(*inst.SupportCode) } addr := net.JoinHostPort(*inst.PrivateIpAddress, strconv.Itoa(d.cfg.Port)) diff --git a/discovery/aws/lightsail_test.go b/discovery/aws/lightsail_test.go new file mode 100644 index 00000000000..7cfcc4f3458 --- /dev/null +++ b/discovery/aws/lightsail_test.go @@ -0,0 +1,181 @@ +// Copyright The Prometheus Authors +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package aws + +import ( + "context" + "testing" + + "github.com/aws/aws-sdk-go-v2/service/lightsail" + "github.com/aws/aws-sdk-go-v2/service/lightsail/types" + "github.com/prometheus/common/model" + "github.com/stretchr/testify/require" +) + +// newMockLightsailClient returns an adapter whose GetInstances answers with the +// supplied instances, so refresh() can be exercised without reaching AWS. +func newMockLightsailClient(instances []types.Instance) *lightsailClientAdapter { + return &lightsailClientAdapter{ + getInstances: func(_ context.Context, _ *lightsail.GetInstancesInput, _ ...func(*lightsail.Options)) (*lightsail.GetInstancesOutput, error) { + return &lightsail.GetInstancesOutput{Instances: instances}, nil + }, + } +} + +func lightsailTestDiscovery(instances []types.Instance) *LightsailDiscovery { + return &LightsailDiscovery{ + lightsail: newMockLightsailClient(instances), + cfg: &LightsailSDConfig{Port: 8080}, + region: "us-east-1", + } +} + +// fullyPopulatedLightsailInstance is the shape the AWS API returns when every +// optional field happens to be set. Each subtest below blanks exactly one of +// them. +func fullyPopulatedLightsailInstance() types.Instance { + return types.Instance{ + PrivateIpAddress: strptr("10.0.0.1"), + BlueprintId: strptr("ubuntu_22_04"), + BundleId: strptr("nano_2_0"), + Name: strptr("instance-1"), + SupportCode: strptr("support-code-1"), + Location: &types.ResourceLocation{AvailabilityZone: strptr("us-east-1a")}, + State: &types.InstanceState{Name: strptr("running")}, + } +} + +// TestLightsailRefreshFullyPopulated pins the happy path so the nil-handling +// added for the cases below cannot silently drop labels that used to be set. +func TestLightsailRefreshFullyPopulated(t *testing.T) { + t.Parallel() + + tgs, err := lightsailTestDiscovery([]types.Instance{fullyPopulatedLightsailInstance()}).refresh(context.Background()) + require.NoError(t, err) + require.Len(t, tgs, 1) + require.Len(t, tgs[0].Targets, 1) + + target := tgs[0].Targets[0] + require.Equal(t, model.LabelValue("10.0.0.1:8080"), target[model.AddressLabel]) + require.Equal(t, model.LabelValue("us-east-1a"), target[lightsailLabelAZ]) + require.Equal(t, model.LabelValue("ubuntu_22_04"), target[lightsailLabelBlueprintID]) + require.Equal(t, model.LabelValue("nano_2_0"), target[lightsailLabelBundleID]) + require.Equal(t, model.LabelValue("instance-1"), target[lightsailLabelInstanceName]) + require.Equal(t, model.LabelValue("running"), target[lightsailLabelInstanceState]) + require.Equal(t, model.LabelValue("support-code-1"), target[lightsailLabelInstanceSupportCode]) +} + +// TestLightsailRefreshNilOptionalFields covers instances where the AWS API +// omitted an optional field. Every field blanked here is a pointer in the SDK +// (Location and State are pointers to structs whose members are themselves +// pointers), and refresh() dereferenced all of them without a nil check, so a +// single missing field panicked the whole Prometheus process during service +// discovery rather than degrading the target. +func TestLightsailRefreshNilOptionalFields(t *testing.T) { + t.Parallel() + + for _, tc := range []struct { + name string + mutate func(*types.Instance) + absent model.LabelName + present map[model.LabelName]model.LabelValue + }{ + { + name: "NilLocation", + mutate: func(i *types.Instance) { i.Location = nil }, + absent: lightsailLabelAZ, + }, + { + name: "NilLocationAvailabilityZone", + mutate: func(i *types.Instance) { i.Location = &types.ResourceLocation{} }, + absent: lightsailLabelAZ, + }, + { + name: "NilState", + mutate: func(i *types.Instance) { i.State = nil }, + absent: lightsailLabelInstanceState, + }, + { + name: "NilStateName", + mutate: func(i *types.Instance) { i.State = &types.InstanceState{} }, + absent: lightsailLabelInstanceState, + }, + { + name: "NilBlueprintId", + mutate: func(i *types.Instance) { i.BlueprintId = nil }, + absent: lightsailLabelBlueprintID, + }, + { + name: "NilBundleId", + mutate: func(i *types.Instance) { i.BundleId = nil }, + absent: lightsailLabelBundleID, + }, + { + name: "NilName", + mutate: func(i *types.Instance) { i.Name = nil }, + absent: lightsailLabelInstanceName, + }, + { + name: "NilSupportCode", + mutate: func(i *types.Instance) { i.SupportCode = nil }, + absent: lightsailLabelInstanceSupportCode, + }, + } { + t.Run(tc.name, func(t *testing.T) { + t.Parallel() + + inst := fullyPopulatedLightsailInstance() + tc.mutate(&inst) + + tgs, err := lightsailTestDiscovery([]types.Instance{inst}).refresh(context.Background()) + require.NoError(t, err) + require.Len(t, tgs, 1) + require.Len(t, tgs[0].Targets, 1, + "instance must still be discovered when an optional field is absent") + + target := tgs[0].Targets[0] + require.NotContains(t, target, tc.absent, + "label sourced from the absent field should be omitted") + // The instance is still usable: the address is what makes it a target. + require.Equal(t, model.LabelValue("10.0.0.1:8080"), target[model.AddressLabel]) + }) + } +} + +// TestLightsailRefreshAllOptionalFieldsNil is the serverless-ish worst case: +// only the private IP is present. It must still yield a scrapeable target. +func TestLightsailRefreshAllOptionalFieldsNil(t *testing.T) { + t.Parallel() + + tgs, err := lightsailTestDiscovery([]types.Instance{ + {PrivateIpAddress: strptr("10.0.0.9")}, + }).refresh(context.Background()) + require.NoError(t, err) + require.Len(t, tgs, 1) + require.Len(t, tgs[0].Targets, 1) + + target := tgs[0].Targets[0] + require.Equal(t, model.LabelValue("10.0.0.9:8080"), target[model.AddressLabel]) + require.Equal(t, model.LabelValue("us-east-1"), target[lightsailLabelRegion]) + for _, absent := range []model.LabelName{ + lightsailLabelAZ, + lightsailLabelBlueprintID, + lightsailLabelBundleID, + lightsailLabelInstanceName, + lightsailLabelInstanceState, + lightsailLabelInstanceSupportCode, + } { + require.NotContains(t, target, absent) + } +} diff --git a/discovery/aws/msk.go b/discovery/aws/msk.go index 14616f84405..dd1f8808c7d 100644 --- a/discovery/aws/msk.go +++ b/discovery/aws/msk.go @@ -308,6 +308,12 @@ func (d *MSKDiscovery) describeClusters(ctx context.Context, clusterARNs []strin if err != nil { return fmt.Errorf("could not describe cluster %v: %w", clusterARN, err) } + // Only provisioned clusters expose broker nodes; skip anything + // else (e.g. serverless clusters) that was explicitly configured. + if cluster.ClusterInfo.ClusterType != types.ClusterTypeProvisioned { + d.logger.Warn("Skipping non-provisioned MSK cluster, only provisioned clusters are supported", "cluster", clusterARN, "type", string(cluster.ClusterInfo.ClusterType)) + return nil + } mu.Lock() clusters = append(clusters, *cluster.ClusterInfo) mu.Unlock() @@ -431,12 +437,17 @@ func (d *MSKDiscovery) refresh(ctx context.Context) ([]*targetgroup.Group, error mskLabelNodeARN: model.LabelValue(aws.ToString(node.NodeARN)), mskLabelNodeAddedTime: model.LabelValue(aws.ToString(node.AddedToClusterTime)), mskLabelNodeInstanceType: model.LabelValue(aws.ToString(node.InstanceType)), - mskLabelClusterJmxExporterEnabled: model.LabelValue(strconv.FormatBool(*cluster.Provisioned.OpenMonitoring.Prometheus.JmxExporter.EnabledInBroker)), mskLabelClusterConfigurationARN: model.LabelValue(aws.ToString(cluster.Provisioned.CurrentBrokerSoftwareInfo.ConfigurationArn)), - mskLabelClusterConfigurationRevision: model.LabelValue(strconv.FormatInt(*cluster.Provisioned.CurrentBrokerSoftwareInfo.ConfigurationRevision, 10)), + mskLabelClusterConfigurationRevision: model.LabelValue(strconv.FormatInt(aws.ToInt64(cluster.Provisioned.CurrentBrokerSoftwareInfo.ConfigurationRevision), 10)), mskLabelClusterKafkaVersion: model.LabelValue(aws.ToString(cluster.Provisioned.CurrentBrokerSoftwareInfo.KafkaVersion)), } + // The JMX exporter label is omitted when Open Monitoring is + // not enabled on the cluster. + if om := cluster.Provisioned.OpenMonitoring; om != nil && om.Prometheus != nil && om.Prometheus.JmxExporter != nil { + labels[mskLabelClusterJmxExporterEnabled] = model.LabelValue(strconv.FormatBool(aws.ToBool(om.Prometheus.JmxExporter.EnabledInBroker))) + } + for key, value := range cluster.Tags { labels[model.LabelName(mskLabelClusterTags+strutil.SanitizeLabelName(key))] = model.LabelValue(value) } @@ -448,7 +459,11 @@ func (d *MSKDiscovery) refresh(ctx context.Context) ([]*targetgroup.Group, error labels[mskLabelBrokerID] = model.LabelValue(fmt.Sprintf("%.0f", aws.ToFloat64(node.BrokerNodeInfo.BrokerId))) labels[mskLabelBrokerClientSubnet] = model.LabelValue(aws.ToString(node.BrokerNodeInfo.ClientSubnet)) labels[mskLabelBrokerClientVPCIP] = model.LabelValue(aws.ToString(node.BrokerNodeInfo.ClientVpcIpAddress)) - labels[mskLabelBrokerNodeExporterEnabled] = model.LabelValue(strconv.FormatBool(*cluster.Provisioned.OpenMonitoring.Prometheus.NodeExporter.EnabledInBroker)) + // The node exporter label is omitted when Open Monitoring + // is not enabled on the cluster. + if om := cluster.Provisioned.OpenMonitoring; om != nil && om.Prometheus != nil && om.Prometheus.NodeExporter != nil { + labels[mskLabelBrokerNodeExporterEnabled] = model.LabelValue(strconv.FormatBool(aws.ToBool(om.Prometheus.NodeExporter.EnabledInBroker))) + } for idx, endpoint := range node.BrokerNodeInfo.Endpoints { endpointLabels := labels.Clone() diff --git a/discovery/aws/msk_test.go b/discovery/aws/msk_test.go index 725d3eeabd8..abd20421597 100644 --- a/discovery/aws/msk_test.go +++ b/discovery/aws/msk_test.go @@ -23,6 +23,7 @@ import ( "github.com/aws/aws-sdk-go-v2/service/kafka" "github.com/aws/aws-sdk-go-v2/service/kafka/types" "github.com/prometheus/common/model" + "github.com/prometheus/common/promslog" "github.com/stretchr/testify/require" "github.com/prometheus/prometheus/discovery/targetgroup" @@ -136,6 +137,41 @@ func TestMSKDiscoveryDescribeClusters(t *testing.T) { clusterARNs []string expected []types.Cluster }{ + { + name: "ServerlessClusterIsSkipped", + mskData: &mskDataStore{ + region: "us-west-2", + clusters: []types.Cluster{ + { + ClusterName: strptr("provisioned-cluster"), + ClusterArn: strptr("arn:aws:kafka:us-west-2:123456789012:cluster/provisioned-cluster/abc-123"), + State: types.ClusterStateActive, + ClusterType: types.ClusterTypeProvisioned, + CurrentVersion: strptr("1.2.3"), + }, + { + ClusterName: strptr("serverless-cluster"), + ClusterArn: strptr("arn:aws:kafka:us-west-2:123456789012:cluster/serverless-cluster/def-456"), + State: types.ClusterStateActive, + ClusterType: types.ClusterTypeServerless, + CurrentVersion: strptr("1.0.0"), + }, + }, + }, + clusterARNs: []string{ + "arn:aws:kafka:us-west-2:123456789012:cluster/provisioned-cluster/abc-123", + "arn:aws:kafka:us-west-2:123456789012:cluster/serverless-cluster/def-456", + }, + expected: []types.Cluster{ + { + ClusterName: strptr("provisioned-cluster"), + ClusterArn: strptr("arn:aws:kafka:us-west-2:123456789012:cluster/provisioned-cluster/abc-123"), + State: types.ClusterStateActive, + ClusterType: types.ClusterTypeProvisioned, + CurrentVersion: strptr("1.2.3"), + }, + }, + }, { name: "SingleCluster", mskData: &mskDataStore{ @@ -218,7 +254,8 @@ func TestMSKDiscoveryDescribeClusters(t *testing.T) { client := newMockMSKClient(tt.mskData) d := &MSKDiscovery{ - msk: client, + msk: client, + logger: promslog.NewNopLogger(), cfg: &MSKSDConfig{ Region: tt.mskData.region, RequestConcurrency: 10, @@ -507,6 +544,123 @@ func TestMSKDiscoveryRefresh(t *testing.T) { }, }, }, + { + name: "ServerlessClusterProducesNoTargets", + mskData: &mskDataStore{ + region: "us-west-2", + clusters: []types.Cluster{ + { + ClusterName: strptr("serverless-cluster"), + ClusterArn: strptr("arn:aws:kafka:us-west-2:123456789012:cluster/serverless-cluster/def-456"), + State: types.ClusterStateActive, + ClusterType: types.ClusterTypeServerless, + CurrentVersion: strptr("1.0.0"), + // Serverless clusters have no Provisioned configuration. + }, + }, + nodes: map[string][]types.NodeInfo{ + "arn:aws:kafka:us-west-2:123456789012:cluster/serverless-cluster/def-456": { + { + NodeARN: strptr("arn:aws:kafka:us-west-2:123456789012:node/broker-2"), + AddedToClusterTime: strptr("2023-01-01T00:00:00Z"), + InstanceType: strptr("kafka.m5.xlarge"), + BrokerNodeInfo: &types.BrokerNodeInfo{ + BrokerId: aws.Float64(2), + ClientSubnet: strptr("subnet-67890"), + ClientVpcIpAddress: strptr("10.0.2.100"), + Endpoints: []string{"b-2.serverless-cluster.def456.kafka.us-west-2.amazonaws.com"}, + AttachedENIId: strptr("eni-67890"), + }, + }, + }, + }, + }, + config: &MSKSDConfig{ + Region: "us-west-2", + Port: 80, + RequestConcurrency: 10, + Clusters: []string{"arn:aws:kafka:us-west-2:123456789012:cluster/serverless-cluster/def-456"}, + }, + // Serverless clusters are skipped by describeClusters, so no + // targets are produced even though the cluster has nodes. + expected: []*targetgroup.Group{ + { + Source: "us-west-2", + }, + }, + }, + { + name: "ProvisionedClusterWithoutOpenMonitoring", + mskData: &mskDataStore{ + region: "us-west-2", + clusters: []types.Cluster{ + { + ClusterName: strptr("no-monitoring-cluster"), + ClusterArn: strptr("arn:aws:kafka:us-west-2:123456789012:cluster/no-monitoring-cluster/ghi-789"), + State: types.ClusterStateActive, + ClusterType: types.ClusterTypeProvisioned, + CurrentVersion: strptr("1.2.3"), + Provisioned: &types.Provisioned{ + CurrentBrokerSoftwareInfo: &types.BrokerSoftwareInfo{ + ConfigurationArn: strptr("arn:aws:kafka:us-west-2:123456789012:configuration/my-config/ghi-789"), + ConfigurationRevision: aws.Int64(2), + KafkaVersion: strptr("2.8.1"), + }, + // Open Monitoring is not enabled on this cluster. + }, + }, + }, + nodes: map[string][]types.NodeInfo{ + "arn:aws:kafka:us-west-2:123456789012:cluster/no-monitoring-cluster/ghi-789": { + { + NodeARN: strptr("arn:aws:kafka:us-west-2:123456789012:node/broker-3"), + AddedToClusterTime: strptr("2023-01-01T00:00:00Z"), + InstanceType: strptr("kafka.m5.large"), + BrokerNodeInfo: &types.BrokerNodeInfo{ + BrokerId: aws.Float64(3), + ClientSubnet: strptr("subnet-12345"), + ClientVpcIpAddress: strptr("10.0.3.100"), + Endpoints: []string{"b-3.no-monitoring-cluster.ghi789.kafka.us-west-2.amazonaws.com"}, + AttachedENIId: strptr("eni-12345"), + }, + }, + }, + }, + }, + config: &MSKSDConfig{ + Region: "us-west-2", + Port: 80, + RequestConcurrency: 10, + Clusters: []string{"arn:aws:kafka:us-west-2:123456789012:cluster/no-monitoring-cluster/ghi-789"}, + }, + expected: []*targetgroup.Group{ + { + Source: "us-west-2", + Targets: []model.LabelSet{ + { + model.AddressLabel: model.LabelValue("b-3.no-monitoring-cluster.ghi789.kafka.us-west-2.amazonaws.com:80"), + "__meta_msk_cluster_name": model.LabelValue("no-monitoring-cluster"), + "__meta_msk_cluster_arn": model.LabelValue("arn:aws:kafka:us-west-2:123456789012:cluster/no-monitoring-cluster/ghi-789"), + "__meta_msk_cluster_state": model.LabelValue("ACTIVE"), + "__meta_msk_cluster_type": model.LabelValue("PROVISIONED"), + "__meta_msk_cluster_version": model.LabelValue("1.2.3"), + "__meta_msk_cluster_configuration_arn": model.LabelValue("arn:aws:kafka:us-west-2:123456789012:configuration/my-config/ghi-789"), + "__meta_msk_cluster_configuration_revision": model.LabelValue("2"), + "__meta_msk_cluster_kafka_version": model.LabelValue("2.8.1"), + "__meta_msk_node_type": model.LabelValue("BROKER"), + "__meta_msk_node_arn": model.LabelValue("arn:aws:kafka:us-west-2:123456789012:node/broker-3"), + "__meta_msk_node_added_time": model.LabelValue("2023-01-01T00:00:00Z"), + "__meta_msk_node_instance_type": model.LabelValue("kafka.m5.large"), + "__meta_msk_node_attached_eni": model.LabelValue("eni-12345"), + "__meta_msk_broker_id": model.LabelValue("3"), + "__meta_msk_broker_client_subnet": model.LabelValue("subnet-12345"), + "__meta_msk_broker_client_vpc_ip": model.LabelValue("10.0.3.100"), + "__meta_msk_broker_endpoint_index": model.LabelValue("0"), + }, + }, + }, + }, + }, { name: "NoClustersWithEmptyClustersConfig", mskData: &mskDataStore{ @@ -1007,6 +1161,7 @@ func TestMSKDiscoveryRefresh(t *testing.T) { d := &MSKDiscovery{ msk: client, + logger: promslog.NewNopLogger(), cfg: config, region: tt.mskData.region, } diff --git a/docs/command-line/prometheus.md b/docs/command-line/prometheus.md index de043a0bf49..36513134d22 100644 --- a/docs/command-line/prometheus.md +++ b/docs/command-line/prometheus.md @@ -64,7 +64,7 @@ The Prometheus monitoring server | --query.timeout | Maximum time a query may take before being aborted. Use with server mode only. | `2m` | | --query.max-concurrency | Maximum number of queries executed concurrently. Use with server mode only. | `20` | | --query.max-samples | Maximum number of samples a single query can load into memory. Note that queries will fail if they try to load more samples than this into memory, so this also limits the number of samples a query can return. Use with server mode only. | `50000000` | -| --enable-feature ... | Comma separated feature names to enable. Valid options: concurrent-rule-eval, created-timestamp-zero-ingestion, delayed-compaction, exemplar-storage, extra-scrape-metrics, histograms-st-encoding, memory-snapshot-on-shutdown, metadata-wal-records, old-ui, otlp-deltatocumulative, otlp-native-delta-ingestion, promql-binop-fill-modifiers, promql-delayed-name-removal, promql-experimental-functions, promql-extended-range-selectors, promql-per-step-stats, search-api, st-storage, st-synthesis, type-and-unit-labels, use-start-timestamps, use-uncached-io, xor2-encoding. See https://prometheus.io/docs/prometheus/latest/feature_flags/ for more details. | | +| --enable-feature ... | Comma separated feature names to enable. Valid options: concurrent-rule-eval, created-timestamp-zero-ingestion, delayed-compaction, exemplar-storage, extra-scrape-metrics, histograms-st-encoding, memory-limiter, memory-snapshot-on-shutdown, metadata-wal-records, old-ui, otlp-deltatocumulative, otlp-native-delta-ingestion, promql-binop-fill-modifiers, promql-delayed-name-removal, promql-experimental-functions, promql-extended-range-selectors, promql-per-step-stats, search-api, st-storage, st-synthesis, type-and-unit-labels, use-start-timestamps, use-uncached-io, xor2-encoding. See https://prometheus.io/docs/prometheus/latest/feature_flags/ for more details. | | | --agent | Run Prometheus in 'Agent mode'. | | | --log.level | Only log messages with the given severity or above. One of: [debug, info, warn, error] | `info` | | --log.format | Output format of log messages. One of: [logfmt, json] | `logfmt` | diff --git a/docs/configuration/configuration.md b/docs/configuration/configuration.md index bb939c39bb6..3d8e2a9f9b5 100644 --- a/docs/configuration/configuration.md +++ b/docs/configuration/configuration.md @@ -1007,10 +1007,10 @@ The following meta labels are available on targets during [relabeling](#relabel_ * `__meta_msk_cluster_name`: the name of the MSK cluster * `__meta_msk_cluster_arn`: the ARN of the MSK cluster * `__meta_msk_cluster_state`: the state of the MSK cluster (e.g., ACTIVE, CREATING, DELETING) -* `__meta_msk_cluster_type`: the type of the MSK cluster (e.g., PROVISIONED, SERVERLESS) +* `__meta_msk_cluster_type`: the type of the MSK cluster (always PROVISIONED, as serverless clusters are skipped) * `__meta_msk_cluster_version`: the current version of the MSK cluster * `__meta_msk_cluster_kafka_version`: the Kafka version running on the cluster -* `__meta_msk_cluster_jmx_exporter_enabled`: whether JMX exporter is enabled on the cluster +* `__meta_msk_cluster_jmx_exporter_enabled`: whether JMX exporter is enabled on the cluster; this label is absent (not `false`) when Open Monitoring is not enabled on the cluster * `__meta_msk_cluster_configuration_arn`: the ARN of the MSK configuration * `__meta_msk_cluster_configuration_revision`: the revision of the MSK configuration * `__meta_msk_cluster_tag_`: each cluster tag value, keyed by tag name @@ -1023,7 +1023,7 @@ The following meta labels are available on targets during [relabeling](#relabel_ * `__meta_msk_broker_endpoint_index`: the index of the broker endpoint (broker nodes only) * `__meta_msk_broker_client_subnet`: the client subnet of the broker (broker nodes only) * `__meta_msk_broker_client_vpc_ip`: the VPC IP address of the broker (broker nodes only) -* `__meta_msk_broker_node_exporter_enabled`: whether node exporter is enabled on brokers (broker nodes only) +* `__meta_msk_broker_node_exporter_enabled`: whether node exporter is enabled on brokers (broker nodes only); this label is absent (not `false`) when Open Monitoring is not enabled on the cluster * `__meta_msk_controller_endpoint_index`: the index of the controller endpoint (controller nodes only) #### `elasticache` @@ -2484,6 +2484,7 @@ Available meta labels: The `pod` role discovers all pods and exposes their containers as targets. For each declared port of a container, a single target is generated. If a container has no specified ports, a port-free target per container is created for manually adding a port via relabeling. +In that case `__address__` is set to the pod IP only, without a port. Available meta labels: @@ -3563,6 +3564,9 @@ You can also use special labels like `__address__`, `__scheme__`, `__metrics_pat override the respective settings in the scrape configuration. The `__address__` label is set to the `:` address of the target. +Some service discovery implementations omit the port when none is known, so +that it can be added via relabeling. Kubernetes pod discovery does this for +containers that declare no ports; `__address__` is then the pod IP only. After relabeling, the `instance` label is set to the value of `__address__` by default if it was not set during relabeling. diff --git a/docs/feature_flags.md b/docs/feature_flags.md index c674347aacf..457eb352234 100644 --- a/docs/feature_flags.md +++ b/docs/feature_flags.md @@ -392,3 +392,10 @@ to this maximum, so an operator setting a smaller cap does not break no-`limit` requests. Setting the flag to `0` disables the cap entirely; this is **not recommended** for endpoints exposed beyond a trusted network because a single client can then request the entire index in one response. + +## Memory limiter + +`--enable-feature=memory-limiter` + +Enables experimental memory limiter monitoring and enforcement. + diff --git a/documentation/examples/remote_storage/go.mod b/documentation/examples/remote_storage/go.mod index d731e0785d0..34937061153 100644 --- a/documentation/examples/remote_storage/go.mod +++ b/documentation/examples/remote_storage/go.mod @@ -1,6 +1,6 @@ module github.com/prometheus/prometheus/documentation/examples/remote_storage -go 1.25.8 +go 1.25.10 require ( github.com/alecthomas/kingpin/v2 v2.4.0 diff --git a/go.mod b/go.mod index ad423b02ff6..7dc4d0d460f 100644 --- a/go.mod +++ b/go.mod @@ -1,6 +1,6 @@ module github.com/prometheus/prometheus -go 1.25.8 +go 1.25.10 require ( github.com/Azure/azure-sdk-for-go/sdk/azcore v1.22.0 @@ -11,17 +11,17 @@ require ( github.com/KimMachineGun/automemlimit v0.7.5 github.com/alecthomas/kingpin/v2 v2.4.0 github.com/alecthomas/units v0.0.0-20240927000941-0f3dac36c52b - github.com/aws/aws-sdk-go-v2 v1.43.0 - github.com/aws/aws-sdk-go-v2/config v1.32.31 - github.com/aws/aws-sdk-go-v2/credentials v1.19.30 - github.com/aws/aws-sdk-go-v2/service/ec2 v1.317.0 - github.com/aws/aws-sdk-go-v2/service/ecs v1.89.0 - github.com/aws/aws-sdk-go-v2/service/elasticache v1.56.0 - github.com/aws/aws-sdk-go-v2/service/kafka v1.56.0 - github.com/aws/aws-sdk-go-v2/service/lightsail v1.58.0 - github.com/aws/aws-sdk-go-v2/service/rds v1.123.0 - github.com/aws/aws-sdk-go-v2/service/sts v1.45.0 - github.com/aws/smithy-go v1.27.4 + github.com/aws/aws-sdk-go-v2 v1.43.4 + github.com/aws/aws-sdk-go-v2/config v1.32.35 + github.com/aws/aws-sdk-go-v2/credentials v1.19.34 + github.com/aws/aws-sdk-go-v2/service/ec2 v1.321.0 + github.com/aws/aws-sdk-go-v2/service/ecs v1.90.0 + github.com/aws/aws-sdk-go-v2/service/elasticache v1.56.4 + github.com/aws/aws-sdk-go-v2/service/kafka v1.58.0 + github.com/aws/aws-sdk-go-v2/service/lightsail v1.58.4 + github.com/aws/aws-sdk-go-v2/service/rds v1.124.1 + github.com/aws/aws-sdk-go-v2/service/sts v1.45.4 + github.com/aws/smithy-go v1.27.7 github.com/bboreham/go-loser v0.0.0-20230920113527-fcc2c21820a3 github.com/cespare/xxhash/v2 v2.3.0 github.com/dennwc/varint v1.0.0 @@ -37,21 +37,21 @@ require ( github.com/gogo/protobuf v1.3.2 github.com/golang/snappy v1.0.0 github.com/google/go-cmp v0.7.0 - github.com/google/pprof v0.0.0-20260709232956-b9395ee17fa0 + github.com/google/pprof v0.0.0-20260802141513-ef3492d7dac3 github.com/google/uuid v1.6.0 github.com/gophercloud/gophercloud/v2 v2.13.0 github.com/grafana/regexp v0.0.0-20250905093917-f7b3be9d1853 github.com/hashicorp/consul/api v1.33.7 - github.com/hashicorp/nomad/api v0.0.0-20260724112153-37c73b2918bd + github.com/hashicorp/nomad/api v0.0.0-20260807203101-d78b9b59529a github.com/hetznercloud/hcloud-go/v2 v2.47.0 github.com/ionos-cloud/sdk-go/v6 v6.3.11 github.com/json-iterator/go v1.1.12 - github.com/klauspost/compress v1.19.1 + github.com/klauspost/compress v1.19.2 github.com/kolo/xmlrpc v0.0.0-20220921171641-a4b6fa1dd06b github.com/linode/linodego v1.69.1 github.com/miekg/dns v1.1.72 github.com/moby/moby/api v1.55.0 - github.com/moby/moby/client v0.5.0 + github.com/moby/moby/client v0.5.1 github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 github.com/mwitkow/go-conntrack v0.0.0-20190716064945-2f068394615f github.com/nsf/jsondiff v0.0.0-20260207060731-8e8d90c4c0ac @@ -70,7 +70,7 @@ require ( github.com/prometheus/common/assets v0.2.0 github.com/prometheus/exporter-toolkit v0.17.1 github.com/prometheus/sigv4 v0.4.1 - github.com/scaleway/scaleway-sdk-go v1.0.0-beta.36 + github.com/scaleway/scaleway-sdk-go v1.0.0-beta.37 github.com/shurcooL/httpfs v0.0.0-20230704072500-f1e31cf0ba5c github.com/stackitcloud/stackit-sdk-go/core v0.26.0 github.com/stretchr/testify v1.11.1 @@ -99,9 +99,9 @@ require ( golang.org/x/sys v0.47.0 golang.org/x/text v0.40.0 google.golang.org/api v0.290.0 - google.golang.org/genproto/googleapis/api v0.0.0-20260724162435-b2f20204f0df + google.golang.org/genproto/googleapis/api v0.0.0-20260807164820-c8921c73eeea google.golang.org/grpc v1.82.1 - google.golang.org/protobuf v1.36.12-0.20260120151049-f2248ac996af + google.golang.org/protobuf v1.36.12-0.20260806062936-644d0267c26e k8s.io/api v0.35.3 k8s.io/apimachinery v0.35.3 k8s.io/client-go v0.35.3 @@ -118,8 +118,8 @@ require ( require ( github.com/aws/aws-sdk-go v1.55.8 // indirect - github.com/aws/aws-sdk-go-v2/internal/v4a v1.4.32 // indirect - github.com/aws/aws-sdk-go-v2/service/signin v1.5.0 // indirect + github.com/aws/aws-sdk-go-v2/internal/v4a v1.4.36 // indirect + github.com/aws/aws-sdk-go-v2/service/signin v1.5.4 // indirect github.com/bahlo/generic-list-go v0.2.0 // indirect github.com/basgys/goxml2json v1.1.1-0.20231018121955-e66ee54ceaad // indirect github.com/buger/jsonparser v1.1.2 // indirect @@ -156,13 +156,13 @@ require ( github.com/AzureAD/microsoft-authentication-library-for-go v1.7.2 // indirect github.com/Microsoft/go-winio v0.6.2 // indirect github.com/armon/go-metrics v0.4.1 // indirect - github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.18.31 - github.com/aws/aws-sdk-go-v2/internal/configsources v1.4.31 // indirect - github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.7.31 // indirect - github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.13.13 // indirect - github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.13.31 // indirect - github.com/aws/aws-sdk-go-v2/service/sso v1.33.0 // indirect - github.com/aws/aws-sdk-go-v2/service/ssooidc v1.38.0 // indirect + github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.18.35 + github.com/aws/aws-sdk-go-v2/internal/configsources v1.4.35 // indirect + github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.7.35 // indirect + github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.13.15 // indirect + github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.13.35 // indirect + github.com/aws/aws-sdk-go-v2/service/sso v1.33.4 // indirect + github.com/aws/aws-sdk-go-v2/service/ssooidc v1.38.4 // indirect github.com/beorn7/perks v1.0.1 // indirect github.com/cenkalti/backoff/v5 v5.0.3 github.com/cncf/xds/go v0.0.0-20260202195803-dba9d589def2 // indirect @@ -253,7 +253,7 @@ require ( golang.org/x/term v0.45.0 // indirect golang.org/x/time v0.15.0 golang.org/x/tools v0.48.0 // indirect - google.golang.org/genproto/googleapis/rpc v0.0.0-20260720155508-bb71a54f79dc // indirect + google.golang.org/genproto/googleapis/rpc v0.0.0-20260729162451-8efbd57d26e0 // indirect gopkg.in/evanphx/json-patch.v4 v4.13.0 // indirect gopkg.in/inf.v0 v0.9.1 // indirect gopkg.in/ini.v1 v1.67.2 // indirect diff --git a/go.sum b/go.sum index 41661183200..67ab48e4f79 100644 --- a/go.sum +++ b/go.sum @@ -43,46 +43,46 @@ github.com/armon/go-metrics v0.4.1 h1:hR91U9KYmb6bLBYLQjyM+3j+rcd/UhE+G78SFnF8gJ github.com/armon/go-metrics v0.4.1/go.mod h1:E6amYzXo6aW1tqzoZGT755KkbgrJsSdpwZ+3JqfkOG4= github.com/aws/aws-sdk-go v1.55.8 h1:JRmEUbU52aJQZ2AjX4q4Wu7t4uZjOu71uyNmaWlUkJQ= github.com/aws/aws-sdk-go v1.55.8/go.mod h1:ZkViS9AqA6otK+JBBNH2++sx1sgxrPKcSzPPvQkUtXk= -github.com/aws/aws-sdk-go-v2 v1.43.0 h1:fharf/WhbRAVZ1du0QL7roNFxZ6T/sWr+4Ni617bwSI= -github.com/aws/aws-sdk-go-v2 v1.43.0/go.mod h1:5pKeft2eJj+gElQ38Jqg4ibCqh+/AK33/0X3hip7IjM= -github.com/aws/aws-sdk-go-v2/config v1.32.31 h1:n4nY9O3QKoHIkL85EX+V8RcMFtOhlpTFhGArg915PXk= -github.com/aws/aws-sdk-go-v2/config v1.32.31/go.mod h1:PN0NYDCCoOpGGsZ2+elDUidmHfQBPyYzN2GCgl8HEBs= -github.com/aws/aws-sdk-go-v2/credentials v1.19.30 h1:TTCvvzFU6gXa4iJecNG/0F/B0oYTiazoRECr2XyLHrY= -github.com/aws/aws-sdk-go-v2/credentials v1.19.30/go.mod h1:jKxAp2AEncnliinzpgOSZDFv6+VjvWhjw/AtbfsWT9U= -github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.18.31 h1:kfVL5wAunCJycL6MOQ6aNh6PlAYEymflcjuKmrWUA0o= -github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.18.31/go.mod h1:nWfRNDAppujCQgOUd43lKT4yeLv9z3nJ3bw1G3BgQKo= -github.com/aws/aws-sdk-go-v2/internal/configsources v1.4.31 h1:Z8F3hfCY33IGpJjFAnv0wvtv1FIKj1GHmRDEYqy64tw= -github.com/aws/aws-sdk-go-v2/internal/configsources v1.4.31/go.mod h1:aVyUoytEyOViR6jhq6jula0xkc5NfBE2hgeF6BvOrao= -github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.7.31 h1:hyOxUyXdh3AyjE93gBgsfziJag9ACwcs+ZpDBLzi8mw= -github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.7.31/go.mod h1:OERqI9k0draSLB8O8woxY3q25ZWTELRK4RRoLMuMZFo= -github.com/aws/aws-sdk-go-v2/internal/v4a v1.4.32 h1:0MrUL35H/Y4kdFfItoR5jCgtDQ4Z/8LudAoIHRfA4hE= -github.com/aws/aws-sdk-go-v2/internal/v4a v1.4.32/go.mod h1:2tNZkuWz54arj8mHVf+8Y7cKkcD8Wr/fBpENgEXpjLc= -github.com/aws/aws-sdk-go-v2/service/ec2 v1.317.0 h1:IkqA16g2hkQntk/K5+srT65TueoTDa7vGhZwqG9w6T4= -github.com/aws/aws-sdk-go-v2/service/ec2 v1.317.0/go.mod h1:dmz3SHr11/hwUijR6xfE/xDRNHcjJwJWZ9ASZdkjGeg= -github.com/aws/aws-sdk-go-v2/service/ecs v1.89.0 h1:Y2xyDc+4y7PX7VeT9ZSxyaorH4I4jx5rPJN8V/FRqso= -github.com/aws/aws-sdk-go-v2/service/ecs v1.89.0/go.mod h1:hntrqC7aHKhK1Q6DX1QEZHH+qkqnhiR/pFCjH0ik5nA= -github.com/aws/aws-sdk-go-v2/service/elasticache v1.56.0 h1:KwkgsVklj6heo6xV3Go+KNbGtJGv80+u7lnU7Mw3R64= -github.com/aws/aws-sdk-go-v2/service/elasticache v1.56.0/go.mod h1:jNvxVh9nmK+pamcs+77YWzwFdDK/HuUNLqisJw++0Nk= -github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.13.13 h1:mbRIur/BiHK6SKPjoBIXSE/hJ6g6JGRLuxQy1jGjlN4= -github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.13.13/go.mod h1:ITg9em2KbJx1s0y4aqRX5OYWG6HBZ5TVR//OdpEZ2CQ= -github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.13.31 h1:w2SIhW92DZPFrSL4ksVCr8IYff5OZwIcxg8+95tzvAI= -github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.13.31/go.mod h1:wAhpCQbkov+IcvjozJbd2xRCoZybUEHNkcFunssNACg= -github.com/aws/aws-sdk-go-v2/service/kafka v1.56.0 h1:QSvI/3ND6Pgx0DQB0i09gfypwzHotyNt94kzXcuXnvY= -github.com/aws/aws-sdk-go-v2/service/kafka v1.56.0/go.mod h1:dTPUh1Cv2uHm3h4bwrpUuJo4OQdcHFozlRgw4N/t+E8= -github.com/aws/aws-sdk-go-v2/service/lightsail v1.58.0 h1:3G/SvYzR+GTA8j9ig3gmPmIo8+eHc2Ap90NpGF/xEyo= -github.com/aws/aws-sdk-go-v2/service/lightsail v1.58.0/go.mod h1:amWiEyivo1ZzJkMQbiCE9wd/dBoql68C/m2RLB3YCQA= -github.com/aws/aws-sdk-go-v2/service/rds v1.123.0 h1:RZFP5elGZ7WRYuLScbx41DPUQaWfYadpywZij9z9p8U= -github.com/aws/aws-sdk-go-v2/service/rds v1.123.0/go.mod h1:3SltwJWYlbf00Rh02s42VpyHl+YMk34UA3+R/zb76dw= -github.com/aws/aws-sdk-go-v2/service/signin v1.5.0 h1:OHH5iTQvVGmfHjX/5Q+vFuA/Rf2x6/95aJ/75QCQSm4= -github.com/aws/aws-sdk-go-v2/service/signin v1.5.0/go.mod h1:mCF3AK9PpL49oOrhniUXWAfhVBVQ/XbytoE5eccZUIs= -github.com/aws/aws-sdk-go-v2/service/sso v1.33.0 h1:CaJyYhxBE0M/HJX/YvSaSmQlsI91VHB0lKU8LtLxL3A= -github.com/aws/aws-sdk-go-v2/service/sso v1.33.0/go.mod h1:+e6BMRMPjBQoCw/WovYR9GLy2IU0z4Q77smOB1DraSg= -github.com/aws/aws-sdk-go-v2/service/ssooidc v1.38.0 h1:tC323YV77QdafeBr6LUhLDTsboyuyHLNRwAyCP44kGU= -github.com/aws/aws-sdk-go-v2/service/ssooidc v1.38.0/go.mod h1:SfLK1sgviHmbI+MozR9iDwDjL4cdCVZtahsjoR+z7wg= -github.com/aws/aws-sdk-go-v2/service/sts v1.45.0 h1:Pd6PNlp4t8PTXxqzstICl52Wsy78vpjFZ7PRUj44mJc= -github.com/aws/aws-sdk-go-v2/service/sts v1.45.0/go.mod h1:rmQ0TnHzuLPmabgjPcsywhsSOmaBDgzR4zvDxSPsGdg= -github.com/aws/smithy-go v1.27.4 h1:JQcphmBN4f0q/sPqXqROIItRNV/hy10cgu7CsFy616M= -github.com/aws/smithy-go v1.27.4/go.mod h1:YE2RhdIuDbA5E5bTdciG9KrW3+TiEONeUWCqxX9i1Fc= +github.com/aws/aws-sdk-go-v2 v1.43.4 h1:b9FTvbRwy+JCsfp2Wp6wV/KbOx3Aj7nkoFb2cRX0IhE= +github.com/aws/aws-sdk-go-v2 v1.43.4/go.mod h1:70vwSy16txshwG+g55WkpgPKDIByzHI8ccBsOteo3bQ= +github.com/aws/aws-sdk-go-v2/config v1.32.35 h1:UEzXuET8E42lxBPijuACu/tEK7v5lFPlk0Q+GT5WD9E= +github.com/aws/aws-sdk-go-v2/config v1.32.35/go.mod h1:KaMtJpFa2JlL2BStjjHQVwQpzZEmw+ND/EgVrfFoo2g= +github.com/aws/aws-sdk-go-v2/credentials v1.19.34 h1:y6GkSmcv5myd1ngrYbGmiLlwQqB6TQhOuN/tbSSuWDY= +github.com/aws/aws-sdk-go-v2/credentials v1.19.34/go.mod h1:w3dTcnDVoQIewjo7JG45hduAToikiIFLC4FIO7fndvw= +github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.18.35 h1:+S7kbJoLDDQ5tE+lHrUBgMkzC8NLgsaioS2F3dVoFAE= +github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.18.35/go.mod h1:Ak7xXviIARfFdNUJ9Etb0bdVDt/KAvKjMGJVLWXDzik= +github.com/aws/aws-sdk-go-v2/internal/configsources v1.4.35 h1:kzVuGlatQtYinwBJEEyLAbggepCoavosiaHHX9+fD+c= +github.com/aws/aws-sdk-go-v2/internal/configsources v1.4.35/go.mod h1:0yLx0yEI+SfqeJMPvOtIEFoZbiQYXMGszBueiutQyaI= +github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.7.35 h1:WK6CjihTuLisCjSKKbildJ79sGZZgbBz3iNa7VsKIhU= +github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.7.35/go.mod h1:KYleN57luLoe97R7vTnx8PMcVrr9gAcRECtOjl91DNg= +github.com/aws/aws-sdk-go-v2/internal/v4a v1.4.36 h1:jbGY4CXLzZElOXgGsexlC3Hi+3YM0rSmk4opFXKqg/k= +github.com/aws/aws-sdk-go-v2/internal/v4a v1.4.36/go.mod h1:uBu/9aKsS/UQGc72RAt3y54kjgYQxmhut8ZD2dXCDNE= +github.com/aws/aws-sdk-go-v2/service/ec2 v1.321.0 h1:XxzwotCCRk2Un1OWcJujk4vAC2OZkGh5l816W1w+Fd8= +github.com/aws/aws-sdk-go-v2/service/ec2 v1.321.0/go.mod h1:Gi5mEHpABbT34fHwafgyxqrIte9oHUEHscusPBYEdHA= +github.com/aws/aws-sdk-go-v2/service/ecs v1.90.0 h1:uxOo7ZIoUh64cKhwC+zUY2A8oT7ZDdAjy5TvKr6KI6U= +github.com/aws/aws-sdk-go-v2/service/ecs v1.90.0/go.mod h1:HWkTC7ipdH6ZoideRpfI19PRRttgNPx8wlLnc9gdYKw= +github.com/aws/aws-sdk-go-v2/service/elasticache v1.56.4 h1:ApnIXsRMPkYY4ehi+SVuSmarkvWerqIncHtR2jPFthI= +github.com/aws/aws-sdk-go-v2/service/elasticache v1.56.4/go.mod h1:cOZC/yZzWPVLKlsEyvgzaGQUisyPcTAf4dPbRPekl9s= +github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.13.15 h1:JJLBQxwY+AFwuPAi5ivGc1ChnTdUt4cXMv7e76m2c/Y= +github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.13.15/go.mod h1:lQknBIe78MVL0cQOQDlag8KGflMbMEVFx9mB6O8ENvk= +github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.13.35 h1:BBEElKh4a+rKshvjrfpajTe9CbpZvrbb4Jkg2PB7RzA= +github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.13.35/go.mod h1:zaZk983w//8beSruBVec/mr4CmDwgZitW/qzGhAAX0g= +github.com/aws/aws-sdk-go-v2/service/kafka v1.58.0 h1:BCICELe5Rikdixq8xpJUPaNHrb+e/wJHqinbkQyXTNU= +github.com/aws/aws-sdk-go-v2/service/kafka v1.58.0/go.mod h1:v4Wwc/lfF7eoE/dezUXD46lpQ/B1B4Cv5w+XPOGfHx0= +github.com/aws/aws-sdk-go-v2/service/lightsail v1.58.4 h1:3xiX3K+xCkmiXHOnaGObetNTdyGOHtig0wRQmob2IMg= +github.com/aws/aws-sdk-go-v2/service/lightsail v1.58.4/go.mod h1:N8LWfjmCQPRevqQ30Qh/M5BKDD1JV4NIdXt9BkK5Fiw= +github.com/aws/aws-sdk-go-v2/service/rds v1.124.1 h1:tEeu5kuP2MLQ7drmlN4qYiBKVoUftyBiS6dSFN67pYc= +github.com/aws/aws-sdk-go-v2/service/rds v1.124.1/go.mod h1:qciN0v66sYiwRf+YRkus1mQR0XldavqGIQEzTxc2vb0= +github.com/aws/aws-sdk-go-v2/service/signin v1.5.4 h1:cOJELVNrq5Q3Udry2GLuHUM7MhwpeaQRdYaoa6GI/yI= +github.com/aws/aws-sdk-go-v2/service/signin v1.5.4/go.mod h1:f4LxzKBtaTxD7xh3PiVg3CE1tchQemfmghaJr+NbK2c= +github.com/aws/aws-sdk-go-v2/service/sso v1.33.4 h1:AMW7a7S8iQaHjBYZdU3PCq4GKRPijTPRAc7e6XtEThY= +github.com/aws/aws-sdk-go-v2/service/sso v1.33.4/go.mod h1:QQNsFV1DVXoXcZt18FS8lI8rtUrlDyAuWZLQ5shunv4= +github.com/aws/aws-sdk-go-v2/service/ssooidc v1.38.4 h1:AsbZcJAQPRmHDJG8K1N0pof/1zPWjVT8TFlTWuGLSvo= +github.com/aws/aws-sdk-go-v2/service/ssooidc v1.38.4/go.mod h1:6imqztH0//t0mKbl6yWl7swSEl7F/w32oAmqB3vP1ag= +github.com/aws/aws-sdk-go-v2/service/sts v1.45.4 h1:w/AryDYMjSUANSQ2uoZxJovUsMTwWJNTv3IMex30Y+4= +github.com/aws/aws-sdk-go-v2/service/sts v1.45.4/go.mod h1:WeBiAa67azG7Su9Vf+ChGDBLiAozJCXzdjXiPBUwtbc= +github.com/aws/smithy-go v1.27.7 h1:Zgj5z4LfcDYoQIVk+n/yGdTkP/2y6ZT5vYxe0fp7bqE= +github.com/aws/smithy-go v1.27.7/go.mod h1:YE2RhdIuDbA5E5bTdciG9KrW3+TiEONeUWCqxX9i1Fc= github.com/bahlo/generic-list-go v0.2.0 h1:5sz/EEAK+ls5wF+NeqDpk5+iNdMDXrh3z3nPnH1Wvgk= github.com/bahlo/generic-list-go v0.2.0/go.mod h1:2KvAjgMlE5NNynlg/5iLrrCCZ2+5xWbdbCW3pNTGyYg= github.com/basgys/goxml2json v1.1.1-0.20231018121955-e66ee54ceaad h1:3swAvbzgfaI6nKuDDU7BiKfZRdF+h2ZwKgMHd8Ha4t8= @@ -250,8 +250,8 @@ github.com/google/go-querystring v1.2.0 h1:yhqkPbu2/OH+V9BfpCVPZkNmUXhb2gBxJArfh github.com/google/go-querystring v1.2.0/go.mod h1:8IFJqpSRITyJ8QhQ13bmbeMBDfmeEJZD5A0egEOmkqU= github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= github.com/google/pprof v0.0.0-20240227163752-401108e1b7e7/go.mod h1:czg5+yv1E0ZGTi6S6vVK1mke0fV+FaUhNGcd6VRS9Ik= -github.com/google/pprof v0.0.0-20260709232956-b9395ee17fa0 h1:du0WGc8xSKq/++e0cglxhS/mXVqsR7+c7jLEi5Vqduw= -github.com/google/pprof v0.0.0-20260709232956-b9395ee17fa0/go.mod h1:MxpfABSjhmINe3F1It9d+8exIHFvUqtLIRCdOGNXqiI= +github.com/google/pprof v0.0.0-20260802141513-ef3492d7dac3 h1:LMLX+LgTNWpfvCBdFebv6EsYotImrt/Ppc5cXIriCSo= +github.com/google/pprof v0.0.0-20260802141513-ef3492d7dac3/go.mod h1:jl5iWTm0/hd5PjEYEOuwAJ57L/CibdZfrqZ5XA5GrCk= github.com/google/s2a-go v0.1.9 h1:LGD7gtMgezd8a/Xak7mEWL0PjoTQFvpRudN895yqKW0= github.com/google/s2a-go v0.1.9/go.mod h1:YA0Ei2ZQL3acow2O62kdp9UlnvMmU7kA6Eutn0dXayM= github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0= @@ -309,8 +309,8 @@ github.com/hashicorp/golang-lru v1.0.2 h1:dV3g9Z/unq5DpblPpw+Oqcv4dU/1omnb4Ok8iP github.com/hashicorp/golang-lru v1.0.2/go.mod h1:iADmTwqILo4mZ8BN3D2Q6+9jd8WM5uGBxy+E8yxSoD4= github.com/hashicorp/memberlist v0.6.0 h1:hhVDLQUzWkLaitLLSrxLLqSD2l2+qiOz1DMr5zb9EQQ= github.com/hashicorp/memberlist v0.6.0/go.mod h1:a2lqh8KICpm8JibWOmuld7DaA+9QU1YcUtTTTMAtt/M= -github.com/hashicorp/nomad/api v0.0.0-20260724112153-37c73b2918bd h1:wznQR/Ba48RMaoWhuJnhLXm4kyT7FWDybBoORxFQl7w= -github.com/hashicorp/nomad/api v0.0.0-20260724112153-37c73b2918bd/go.mod h1:Gnzrrc6H3OackqTmXNoGN30v347WpaX6oPZDJRSwX8A= +github.com/hashicorp/nomad/api v0.0.0-20260807203101-d78b9b59529a h1:WalN0KEQK4jFJc/rR2m1YjLfxdj2woWaFJZuCMRTtKI= +github.com/hashicorp/nomad/api v0.0.0-20260807203101-d78b9b59529a/go.mod h1:Gnzrrc6H3OackqTmXNoGN30v347WpaX6oPZDJRSwX8A= github.com/hashicorp/serf v0.10.4 h1:TCQOrJXHZ1Xf80c4WBhMM9OwUFgDaIP0R+YvoQUKadI= github.com/hashicorp/serf v0.10.4/go.mod h1:l+s5Q1OSPWU6b9l9m7ODJzTp7mLevSaVzAI03Nka2F0= github.com/hetznercloud/hcloud-go/v2 v2.47.0 h1:SI7C4cvdYReb2aHUEQ8KBMOqxNnmd4hOZti1SbPq3Qk= @@ -338,8 +338,8 @@ github.com/keybase/go-keychain v0.0.1 h1:way+bWYa6lDppZoZcgMbYsvC7GxljxrskdNInRt github.com/keybase/go-keychain v0.0.1/go.mod h1:PdEILRW3i9D8JcdM+FmY6RwkHGnhHxXwkPPMeUgOK1k= github.com/kisielk/errcheck v1.5.0/go.mod h1:pFxgyoBC7bSaBwPgfKdkLd5X25qrDl4LWUI2bnpBCr8= github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck= -github.com/klauspost/compress v1.19.1 h1:VsB4HPswih7mmZ8WleSFQ75c/Ui1M4trX5oAsJnhSlk= -github.com/klauspost/compress v1.19.1/go.mod h1:cwPg85FWrGar70rWktvGQj8/hthj3wpl0PGDogxkrSQ= +github.com/klauspost/compress v1.19.2 h1:hMRETovs/pu/dVWN7zIT1PGG8t509MwT6bO7XSi26R8= +github.com/klauspost/compress v1.19.2/go.mod h1:cwPg85FWrGar70rWktvGQj8/hthj3wpl0PGDogxkrSQ= github.com/knadh/koanf/maps v0.1.2 h1:RBfmAW5CnZT+PJ1CVc1QSJKf4Xu9kxfQgYVQSu8hpbo= github.com/knadh/koanf/maps v0.1.2/go.mod h1:npD/QZY3V6ghQDdcQzl1W4ICNVTkohC8E73eI2xW4yI= github.com/knadh/koanf/providers/confmap v1.0.0 h1:mHKLJTE7iXEys6deO5p6olAiZdG5zwp8Aebir+/EaRE= @@ -390,8 +390,8 @@ github.com/moby/docker-image-spec v1.3.1 h1:jMKff3w6PgbfSa69GfNg+zN/XLhfXJGnEx3N github.com/moby/docker-image-spec v1.3.1/go.mod h1:eKmb5VW8vQEh/BAr2yvVNvuiJuY6UIocYsFu/DxxRpo= github.com/moby/moby/api v1.55.0 h1:2/sexvQyqIWS8pRSCFddBfpW2qE7vR7FCL+vN8pxwMc= github.com/moby/moby/api v1.55.0/go.mod h1:+RQ6wluLwtYaTd1WnPLykIDPekkuyD/ROWQClE83pzs= -github.com/moby/moby/client v0.5.0 h1:5XhyPk2fuOWf6RlSFa3MkIIgDZkF25xToXW8Q/BH7cc= -github.com/moby/moby/client v0.5.0/go.mod h1:rcVpF8ncl9vo5gaIBdol6CnbEtSj1uxMvEV/UrykF/s= +github.com/moby/moby/client v0.5.1 h1:tYNaJno4c0HXz12y5BiqEDy0rVTYkWzI26lGvnTMiJw= +github.com/moby/moby/client v0.5.1/go.mod h1:odLstlZ6uSnfvAgVxMpvgmb8SUdd+siH2T0GBuxVAlM= 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= @@ -493,8 +493,8 @@ github.com/rogpeppe/go-internal v1.14.1 h1:UQB4HGPB6osV0SQTLymcB4TgvyWu6ZyliaW0t github.com/rogpeppe/go-internal v1.14.1/go.mod h1:MaRKkUm5W0goXpeCfT7UZI6fk/L7L7so1lCWt35ZSgc= github.com/santhosh-tekuri/jsonschema/v6 v6.0.2 h1:KRzFb2m7YtdldCEkzs6KqmJw4nqEVZGK7IN2kJkjTuQ= github.com/santhosh-tekuri/jsonschema/v6 v6.0.2/go.mod h1:JXeL+ps8p7/KNMjDQk3TCwPpBy0wYklyWTfbkIzdIFU= -github.com/scaleway/scaleway-sdk-go v1.0.0-beta.36 h1:ObX9hZmK+VmijreZO/8x9pQ8/P/ToHD/bdSb4Eg4tUo= -github.com/scaleway/scaleway-sdk-go v1.0.0-beta.36/go.mod h1:LEsDu4BubxK7/cWhtlQWfuxwL4rf/2UEpxXz1o1EMtM= +github.com/scaleway/scaleway-sdk-go v1.0.0-beta.37 h1:1Q6K8D0BagYYEnCTkT9fn3YHUFb06bS1OvIHWcc3JQM= +github.com/scaleway/scaleway-sdk-go v1.0.0-beta.37/go.mod h1:Rtb4r3WZ5x4AqmL3t/wiF/DmQi+7GlU/nCRdqFbClV4= github.com/sean-/seed v0.0.0-20170313163322-e2103e2c3529 h1:nn5Wsu0esKSJiIVhscUtVbo7ada43DJhG55ua/hjS5I= github.com/sean-/seed v0.0.0-20170313163322-e2103e2c3529/go.mod h1:DxrIzT+xaE7yg65j358z/aeFdxmN0P9QXhEzd20vsDc= github.com/shoenig/test v1.13.2 h1:SaGxHxg7xkRuKuNtuFmHf0LgNGaAgcBT7HN4WHCKfqU= @@ -721,21 +721,21 @@ google.golang.org/api v0.290.0 h1:eMw0Xo+IfbbMlKmW7aHvpyQRv9RCXuWx/vs8AD+0x9A= google.golang.org/api v0.290.0/go.mod h1:weJZ3lldHFYI0DBFNKpJelUDNnusTt5YaOEgxvt8ci8= google.golang.org/genproto v0.0.0-20260319201613-d00831a3d3e7 h1:XzmzkmB14QhVhgnawEVsOn6OFsnpyxNPRY9QV01dNB0= google.golang.org/genproto v0.0.0-20260319201613-d00831a3d3e7/go.mod h1:L43LFes82YgSonw6iTXTxXUX1OlULt4AQtkik4ULL/I= -google.golang.org/genproto/googleapis/api v0.0.0-20260724162435-b2f20204f0df h1:NsJx+hCSwIBI6+C4BuJIkb8xOG1M+nfQDsqIrQHT92k= -google.golang.org/genproto/googleapis/api v0.0.0-20260724162435-b2f20204f0df/go.mod h1:1brfde68Npq6+WA75c1EHWPijZEG1kMus61ygPZfn4A= -google.golang.org/genproto/googleapis/rpc v0.0.0-20260720155508-bb71a54f79dc h1:3TtNq/QbJNrSY1nVdjcikfBw6ujnaNbdrd88wNr1OW4= -google.golang.org/genproto/googleapis/rpc v0.0.0-20260720155508-bb71a54f79dc/go.mod h1:4Hqkh8ycfw05ld/3BWL7rJOSfebL2Q+DVDeRgYgxUU8= +google.golang.org/genproto/googleapis/api v0.0.0-20260807164820-c8921c73eeea h1:Jifw/kjs/r3B0uszvls/m3c3tmZs2YHGM9C+rvxP9gY= +google.golang.org/genproto/googleapis/api v0.0.0-20260807164820-c8921c73eeea/go.mod h1:K/+WGbmBY7aNW1HDw1fJnKYo10i0DkAX6pows00dLig= +google.golang.org/genproto/googleapis/rpc v0.0.0-20260729162451-8efbd57d26e0 h1:mJiOtnGp0k/BcSgdu03G2NwnscCfCH+h2QKUBZr18KI= +google.golang.org/genproto/googleapis/rpc v0.0.0-20260729162451-8efbd57d26e0/go.mod h1:4Hqkh8ycfw05ld/3BWL7rJOSfebL2Q+DVDeRgYgxUU8= google.golang.org/grpc v1.82.1 h1:NnAxzGRA0677vCa4BUkOAnO5+FfQqVl9iUXeD0IqcGE= google.golang.org/grpc v1.82.1/go.mod h1:yzTZ1TB1Z3SG+LIYaI+WiE8D5+PZ3ArnrSp8zF3+/ZA= -google.golang.org/protobuf v1.36.12-0.20260120151049-f2248ac996af h1:+5/Sw3GsDNlEmu7TfklWKPdQ0Ykja5VEmq2i817+jbI= -google.golang.org/protobuf v1.36.12-0.20260120151049-f2248ac996af/go.mod h1:HTf+CrKn2C3g5S8VImy6tdcUvCska2kB7j23XfzDpco= +google.golang.org/protobuf v1.36.12-0.20260806062936-644d0267c26e h1:EIVWoj7hKWJiXy9OdaukBGcSR+NH3cGL/uswTzfvuec= +google.golang.org/protobuf v1.36.12-0.20260806062936-644d0267c26e/go.mod h1:HTf+CrKn2C3g5S8VImy6tdcUvCska2kB7j23XfzDpco= gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk= gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q= -gopkg.in/dnaeon/go-vcr.v4 v4.0.6 h1:PiJkrakkmzc5s7EfBnZOnyiLwi7o7A9fwPzN0X2uwe0= -gopkg.in/dnaeon/go-vcr.v4 v4.0.6/go.mod h1:sbq5oMEcM4PXngbcNbHhzfCP9OdZodLhrbRYoyg09HY= +gopkg.in/dnaeon/go-vcr.v4 v4.0.7 h1:Mq/RF+mq3QwtEunJSsoTbYPt3elSAmdJhAxrEaqr88I= +gopkg.in/dnaeon/go-vcr.v4 v4.0.7/go.mod h1:cRwV/njsN/D8qNJu4NAXWswz6b4OUh3rMIu4SObbLBg= gopkg.in/evanphx/json-patch.v4 v4.13.0 h1:czT3CmqEaQ1aanPc5SdlgQrrEIb8w/wwCvWWnfEbYzo= gopkg.in/evanphx/json-patch.v4 v4.13.0/go.mod h1:p8EYWUEYMpynmqDbY58zCKCFZw8pRWMG4EsWvDvM72M= gopkg.in/inf.v0 v0.9.1 h1:73M5CoZyi3ZLMOyDlQh031Cx6N9NDJ2Vvfl76EDAgDc= diff --git a/go.work b/go.work index 1382a363def..5f27764ccc7 100644 --- a/go.work +++ b/go.work @@ -1,4 +1,4 @@ -go 1.25.8 +go 1.25.10 use ( . diff --git a/internal/tools/go.mod b/internal/tools/go.mod index 92fdc83f98c..3d3a79a4037 100644 --- a/internal/tools/go.mod +++ b/internal/tools/go.mod @@ -1,6 +1,6 @@ module github.com/prometheus/prometheus/internal/tools -go 1.25.8 +go 1.25.10 require ( github.com/bufbuild/buf v1.72.0 diff --git a/model/histogram/float_histogram.go b/model/histogram/float_histogram.go index 2b17b4c1b9d..a217476b815 100644 --- a/model/histogram/float_histogram.go +++ b/model/histogram/float_histogram.go @@ -822,6 +822,7 @@ func detectReset(currIt, prevIt *floatBucketIterator) bool { if !prevIt.Next() { return false } + prevBucket = prevIt.strippedAt() } } currBucket := currIt.strippedAt() @@ -841,6 +842,7 @@ func detectReset(currIt, prevIt *floatBucketIterator) bool { if !prevIt.Next() { return false } + prevBucket = prevIt.strippedAt() } } currBucket = currIt.strippedAt() diff --git a/model/histogram/float_histogram_test.go b/model/histogram/float_histogram_test.go index 73b1496044d..ad027d8e3ab 100644 --- a/model/histogram/float_histogram_test.go +++ b/model/histogram/float_histogram_test.go @@ -1415,6 +1415,47 @@ func TestFloatHistogramDetectReset(t *testing.T) { }, false, // No reset: all mapped buckets increase }, + { + // The previous histogram's first negative bucket is empty and a + // later one is populated. The current histogram has no negative + // buckets at all, so the populated previous bucket disappeared, + // which is a reset. + "reset when a populated bucket following an empty one disappears", + &FloatHistogram{ + ZeroThreshold: 0.001, + Count: 10, + PositiveSpans: []Span{{0, 1}}, + PositiveBuckets: []float64{5}, + NegativeSpans: []Span{{1, 2}}, + NegativeBuckets: []float64{0, 5}, + }, + &FloatHistogram{ + ZeroThreshold: 0.001, + Count: 20, + PositiveSpans: []Span{{0, 1}}, + PositiveBuckets: []float64{20}, + }, + true, + }, + { + // The current histogram runs out of buckets before a later + // populated bucket of the previous histogram, which sits behind an + // empty one. That populated bucket disappeared, so it is a reset. + "reset when current ends before a later populated previous bucket", + &FloatHistogram{ + ZeroThreshold: 0.001, + Count: 7, + PositiveSpans: []Span{{0, 3}}, + PositiveBuckets: []float64{2, 0, 5}, + }, + &FloatHistogram{ + ZeroThreshold: 0.001, + Count: 100, + PositiveSpans: []Span{{0, 1}}, + PositiveBuckets: []float64{100}, + }, + true, + }, } for _, c := range cases { @@ -1676,6 +1717,22 @@ func TestFloatHistogramCompact(t *testing.T) { NegativeBuckets: []float64{3.1, 3, 0, 0, 0, 1.234e5, 1000, 0, 3, 4}, }, }, + { + "more than one span merged in the same pass", + &FloatHistogram{ + PositiveSpans: []Span{{-2, 2}, {2, 2}, {2, 2}}, + PositiveBuckets: []float64{1, 3.3, 4.2, 0.1, 3.3, 2}, + NegativeSpans: []Span{{0, 1}, {1, 1}, {1, 1}}, + NegativeBuckets: []float64{3.1, 1000, 4}, + }, + 3, + &FloatHistogram{ + PositiveSpans: []Span{{-2, 10}}, + PositiveBuckets: []float64{1, 3.3, 0, 0, 4.2, 0.1, 0, 0, 3.3, 2}, + NegativeSpans: []Span{{0, 5}}, + NegativeBuckets: []float64{3.1, 0, 1000, 0, 4}, + }, + }, { "only empty buckets and maxEmptyBuckets greater zero", &FloatHistogram{ @@ -1776,13 +1833,37 @@ func TestFloatHistogramCompact(t *testing.T) { for _, c := range cases { t.Run(c.name, func(t *testing.T) { + wasValid := c.in.Validate() == nil require.Equal(t, c.expected, c.in.Compact(c.maxEmptyBuckets)) // Compact has happened in-place, too. require.Equal(t, c.expected, c.in) + if wasValid { + require.NoError(t, c.in.Validate(), "Compact turned a valid histogram into an invalid one") + } }) } } +// TestFloatHistogramKahanCompactSpanMerge makes sure the Kahan compensation +// terms stay aligned with the buckets they belong to when more than one span is +// merged in the same pass. +func TestFloatHistogramKahanCompactSpanMerge(t *testing.T) { + h := &FloatHistogram{ + PositiveSpans: []Span{{0, 1}, {1, 1}, {1, 1}}, + PositiveBuckets: []float64{1, 2, 3}, + } + c := &FloatHistogram{ + PositiveSpans: []Span{{0, 1}, {1, 1}, {1, 1}}, + PositiveBuckets: []float64{0.1, 0.2, 0.3}, + } + + h, c = h.kahanCompact(3, c) + + require.Equal(t, []Span{{0, 5}}, h.PositiveSpans) + require.Equal(t, []float64{1, 0, 2, 0, 3}, h.PositiveBuckets) + require.Equal(t, []float64{0.1, 0, 0.2, 0, 0.3}, c.PositiveBuckets) +} + func TestFloatHistogramAdd(t *testing.T) { cases := []struct { name string diff --git a/model/histogram/generic.go b/model/histogram/generic.go index f6ba80a3ae1..64e0ba6786e 100644 --- a/model/histogram/generic.go +++ b/model/histogram/generic.go @@ -476,6 +476,7 @@ func compactBuckets[IBC InternalBucketCount]( } // Merge span with previous one and insert empty buckets. offset := int(spans[iSpan].Offset) + l := int(spans[iSpan].Length) spans[iSpan-1].Length += uint32(offset) + spans[iSpan].Length spans = append(spans[:iSpan], spans[iSpan+1:]...) newPrimaryBuckets := make([]IBC, len(primaryBuckets)+offset) @@ -493,7 +494,18 @@ func compactBuckets[IBC InternalBucketCount]( compensationBuckets = newCompensationBuckets } iBucket += offset - currentBucketAbsolute = primaryBuckets[iBucket] + // The buckets of the merged span are now part of the previous span, so + // iBucket has to skip them as well to keep pointing at the first bucket + // of the span we look at next. The inserted empty buckets have reset the + // running absolute count to zero, so the deltas of the merged span add up + // to the absolute count of its last bucket. + if deltaBuckets { + currentBucketAbsolute = 0 + for _, bucket := range primaryBuckets[iBucket : iBucket+l] { + currentBucketAbsolute += bucket + } + } + iBucket += l // Note that with many merges, it would be more efficient to // first record all the chunks of empty buckets to insert and // then do it in one go through all the buckets. diff --git a/model/histogram/histogram_test.go b/model/histogram/histogram_test.go index 421227ff481..a381019265e 100644 --- a/model/histogram/histogram_test.go +++ b/model/histogram/histogram_test.go @@ -1258,6 +1258,24 @@ func TestHistogramCompact(t *testing.T) { NegativeBuckets: []int64{5, 3, -8, 0, 0, 4, -2, -2, 3, 4}, }, }, + { + "more than one span merged in the same pass", + &Histogram{ + Count: 30, + PositiveSpans: []Span{{0, 2}, {2, 2}, {2, 2}}, + PositiveBuckets: []int64{1, 1, 1, 1, 1, 1}, + NegativeSpans: []Span{{0, 1}, {1, 1}, {1, 1}}, + NegativeBuckets: []int64{2, 1, 1}, + }, + 3, + &Histogram{ + Count: 30, + PositiveSpans: []Span{{0, 10}}, + PositiveBuckets: []int64{1, 1, -2, 0, 3, 1, -4, 0, 5, 1}, + NegativeSpans: []Span{{0, 5}}, + NegativeBuckets: []int64{2, -2, 3, -3, 4}, + }, + }, { "only empty buckets and maxEmptyBuckets greater zero", &Histogram{ @@ -1409,9 +1427,13 @@ func TestHistogramCompact(t *testing.T) { for _, c := range cases { t.Run(c.name, func(t *testing.T) { + wasValid := c.in.Validate() == nil require.Equal(t, c.expected, c.in.Compact(c.maxEmptyBuckets)) // Compact has happened in-place, too. require.Equal(t, c.expected, c.in) + if wasValid { + require.NoError(t, c.in.Validate(), "Compact turned a valid histogram into an invalid one") + } }) } } diff --git a/promql/engine.go b/promql/engine.go index 6e8939afa50..0fa4b7112c5 100644 --- a/promql/engine.go +++ b/promql/engine.go @@ -1843,7 +1843,9 @@ func (ev *evaluator) smoothSeries(series []storage.Series, offset time.Duration, // For every storage.Series iterator in series, the method iterates in ev.interval sized steps from ev.startTimestamp until and including ev.endTimestamp, // collecting every corresponding sample (obtained via ev.vectorSelectorSingle) into a Series. // All of the generated Series are collected into a Matrix, that gets returned. -func (ev *evaluator) evalSeries(ctx context.Context, series []storage.Series, offset time.Duration, recordOrigT bool) Matrix { +// If atTimestamp is non-nil, every step is evaluated as of that fixed timestamp instead of the +// step timestamp; the sample is still emitted at the step timestamp. +func (ev *evaluator) evalSeries(ctx context.Context, series []storage.Series, offset time.Duration, recordOrigT bool, atTimestamp *int64) Matrix { numSteps := int((ev.endTimestamp-ev.startTimestamp)/ev.interval) + 1 mat := make(Matrix, 0, len(series)) @@ -1863,7 +1865,11 @@ func (ev *evaluator) evalSeries(ctx context.Context, series []storage.Series, of for ts, step := ev.startTimestamp, -1; ts <= ev.endTimestamp; ts += ev.interval { step++ - _, origT, f, h, ok := ev.vectorSelectorSingle(it, offset, ts) + lookupTS := ts + if atTimestamp != nil { + lookupTS = *atTimestamp + } + _, origT, f, h, ok := ev.vectorSelectorSingle(it, offset, lookupTS) if !ok { continue } @@ -2542,7 +2548,7 @@ func (ev *evaluator) eval(ctx context.Context, expr parser.Expr) (parser.Value, ws.Merge(smoothAnnos) return mat, ws } - mat := ev.evalSeries(ctx, e.Series, e.Offset, false) + mat := ev.evalSeries(ctx, e.Series, e.Offset, false, nil) return mat, ws case *parser.MatrixSelector: diff --git a/promql/info.go b/promql/info.go index 539e5ad6856..8955d077e09 100644 --- a/promql/info.go +++ b/promql/info.go @@ -19,6 +19,7 @@ import ( "fmt" "slices" "strings" + "time" "github.com/grafana/regexp" "github.com/prometheus/common/model" @@ -37,6 +38,14 @@ var identifyingLabels = []string{"instance", "job"} // evalInfo implements the info PromQL function. func (ev *evaluator) evalInfo(ctx context.Context, args parser.Expressions) (parser.Value, annotations.Annotations) { + // The @ timestamp and offset on the first argument also govern at which time the info + // series are evaluated and matched (not just which series are selected), so that info(v @ T) + // enriches with the info series as of T at every step, independent of the evaluation time. + // They must be extracted before evaluating the first argument: evaluating a subquery + // replaces it in the expression with a materialized matrix selector that no longer carries + // the modifiers of the selectors inside the subquery. + nodeTimestamp, offset := infoSelectTimestampAndOffset(args[0]) + val, annots := ev.eval(ctx, args[0]) mat := val.(Matrix) // Map from data label name to matchers. @@ -72,8 +81,8 @@ func (ev *evaluator) evalInfo(ctx context.Context, args parser.Expressions) (par } } - selectHints := ev.infoSelectHints(args[0]) - infoSeries, ws, err := ev.fetchInfoSeries(ctx, mat, ignoreSeries, dataLabelMatchers, selectHints) + selectHints := ev.infoSelectHints(nodeTimestamp, offset) + infoSeries, ws, err := ev.fetchInfoSeries(ctx, mat, ignoreSeries, dataLabelMatchers, selectHints, nodeTimestamp, offset) if err != nil { ev.error(err) } @@ -104,22 +113,37 @@ func effectiveInfoNameMatchers(matchers []*labels.Matcher) []*labels.Matcher { return []*labels.Matcher{labels.MustNewMatcher(labels.MatchEqual, model.MetricNameLabel, targetInfo)} } -// infoSelectHints calculates the storage.SelectHints for selecting info series, given expr (first argument to info call). -func (ev *evaluator) infoSelectHints(expr parser.Expr) storage.SelectHints { - var nodeTimestamp *int64 - var offset int64 - parser.Inspect(expr, func(node parser.Node, _ []parser.Node) error { - switch n := node.(type) { - case *parser.VectorSelector: - if n.Timestamp != nil { - nodeTimestamp = n.Timestamp - } - offset = durationMilliseconds(n.OriginalOffset) - return errors.New("end traversal") - default: +// infoSelectTimestampAndOffset returns the @ timestamp (nil if unset) and offset that govern +// selection and evaluation of the info series, given expr (the first argument to an info call). +// The reference time is derived from the first vector selector found in expr: the innermost @ +// timestamp among the selector and its enclosing subqueries anchors it (the evaluation time if +// none is set), shifted by the offsets accumulated from the selector up to and including the +// anchoring node. +func infoSelectTimestampAndOffset(expr parser.Expr) (nodeTimestamp *int64, offset time.Duration) { + parser.Inspect(expr, func(node parser.Node, path []parser.Node) error { + n, ok := node.(*parser.VectorSelector) + if !ok { return nil } + nodeTimestamp = n.Timestamp + offset = n.OriginalOffset + // Enclosing subqueries shift the selector's reference time: their offsets add up until + // an @ timestamp anchors it, making any modifiers further out irrelevant. + for i := len(path) - 1; nodeTimestamp == nil && i >= 0; i-- { + if sq, ok := path[i].(*parser.SubqueryExpr); ok { + offset += sq.OriginalOffset + nodeTimestamp = sq.Timestamp + } + } + return errors.New("end traversal") }) + return nodeTimestamp, offset +} + +// infoSelectHints calculates the storage.SelectHints for selecting info series, given the +// @ timestamp (nil if unset) and offset that govern the first argument to the info call. +func (ev *evaluator) infoSelectHints(nodeTimestamp *int64, offset time.Duration) storage.SelectHints { + offsetMs := durationMilliseconds(offset) start := ev.startTimestamp end := ev.endTimestamp @@ -132,8 +156,8 @@ func (ev *evaluator) infoSelectHints(expr parser.Expr) storage.SelectHints { // because wo want to exclude samples that are precisely the // lookback delta before the eval time. start -= durationMilliseconds(ev.lookbackDelta) - 1 - start -= offset - end -= offset + start -= offsetMs + end -= offsetMs return storage.SelectHints{ Start: start, @@ -146,7 +170,7 @@ func (ev *evaluator) infoSelectHints(expr parser.Expr) storage.SelectHints { // fetchInfoSeries fetches info series given matching identifying labels in mat. // Series in ignoreSeries are not fetched. // dataLabelMatchers may be mutated. -func (ev *evaluator) fetchInfoSeries(ctx context.Context, mat Matrix, ignoreSeries map[uint64]struct{}, dataLabelMatchers map[string][]*labels.Matcher, selectHints storage.SelectHints) (Matrix, annotations.Annotations, error) { +func (ev *evaluator) fetchInfoSeries(ctx context.Context, mat Matrix, ignoreSeries map[uint64]struct{}, dataLabelMatchers map[string][]*labels.Matcher, selectHints storage.SelectHints, atTimestamp *int64, offset time.Duration) (Matrix, annotations.Annotations, error) { removeNameFromDataLabelMatchers := func() { for name, ms := range dataLabelMatchers { ms = slices.DeleteFunc(ms, func(m *labels.Matcher) bool { @@ -228,7 +252,10 @@ func (ev *evaluator) fetchInfoSeries(ctx context.Context, mat Matrix, ignoreSeri return nil, ws, err } - infoMat := ev.evalSeries(ctx, infoSeries, 0, true) + // Evaluate the info series at the @-pinned timestamp (when set) and shifted by the offset, + // so enrichment reflects the info series as of the time selected by the first argument's + // modifiers, consistently at every step, rather than the raw evaluation timestamp. + infoMat := ev.evalSeries(ctx, infoSeries, offset, true, atTimestamp) return infoMat, ws, nil } diff --git a/promql/parser/generated_parser.y b/promql/parser/generated_parser.y index c33f3a693aa..da9bc930b2c 100644 --- a/promql/parser/generated_parser.y +++ b/promql/parser/generated_parser.y @@ -650,9 +650,9 @@ matrix_selector : expr LEFT_BRACKET positive_duration_expr RIGHT_BRACKET vs, ok := $1.(*VectorSelector) if !ok{ errMsg = "ranges only allowed for vector selectors" - } else if vs.OriginalOffset != 0{ + } else if vs.OriginalOffset != 0 || vs.OriginalOffsetExpr != nil { errMsg = "no offset modifiers allowed before range" - } else if vs.Timestamp != nil { + } else if vs.Timestamp != nil || vs.StartOrEnd != 0 { errMsg = "no @ modifiers allowed before range" } diff --git a/promql/parser/generated_parser.y.go b/promql/parser/generated_parser.y.go index 17c4833a45d..846d830bdd2 100644 --- a/promql/parser/generated_parser.y.go +++ b/promql/parser/generated_parser.y.go @@ -1711,9 +1711,9 @@ yydefault: vs, ok := yyDollar[1].node.(*VectorSelector) if !ok { errMsg = "ranges only allowed for vector selectors" - } else if vs.OriginalOffset != 0 { + } else if vs.OriginalOffset != 0 || vs.OriginalOffsetExpr != nil { errMsg = "no offset modifiers allowed before range" - } else if vs.Timestamp != nil { + } else if vs.Timestamp != nil || vs.StartOrEnd != 0 { errMsg = "no @ modifiers allowed before range" } diff --git a/promql/parser/parse_test.go b/promql/parser/parse_test.go index 2ea3b7bf5a7..b1912e14de0 100644 --- a/promql/parser/parse_test.go +++ b/promql/parser/parse_test.go @@ -2803,6 +2803,39 @@ var testExpr = []struct { }, }, }, + { + input: `some_metric @ start() [5m]`, + fail: true, + errors: ParseErrors{ + ParseErr{ + PositionRange: posrange.PositionRange{Start: 22, End: 26}, + Err: errors.New("no @ modifiers allowed before range"), + Query: `some_metric @ start() [5m]`, + }, + }, + }, + { + input: `some_metric @ end()[5m]`, + fail: true, + errors: ParseErrors{ + ParseErr{ + PositionRange: posrange.PositionRange{Start: 19, End: 23}, + Err: errors.New("no @ modifiers allowed before range"), + Query: `some_metric @ end()[5m]`, + }, + }, + }, + { + input: `some_metric offset step()[5m]`, + fail: true, + errors: ParseErrors{ + ParseErr{ + PositionRange: posrange.PositionRange{Start: 25, End: 29}, + Err: errors.New("no offset modifiers allowed before range"), + Query: `some_metric offset step()[5m]`, + }, + }, + }, { input: `(foo + bar)[5m]`, fail: true, diff --git a/promql/promqltest/testdata/info.test b/promql/promqltest/testdata/info.test index 647a2023890..174610f3449 100644 --- a/promql/promqltest/testdata/info.test +++ b/promql/promqltest/testdata/info.test @@ -211,6 +211,67 @@ eval range from 1m to 4m step 1m info(metric @ 60) eval range from 1m to 4m step 1m info(metric offset 1m) metric{data="info", instance="a", job="1", label="value"} 0 0 2 3 +# @ operator works also with info in an instant query. +# Because info() evaluates the info series as of the @ timestamp, info(metric @ 60) is step +# invariant: it returns the same result at any evaluation time, so the instant-query test +# harness's @-invariance checks (which re-evaluate at other eval times) hold. +eval instant at 4m info(metric @ 60) + metric{data="info", instance="a", job="1", label="value"} 0 + +clear + +# info() honours the @ modifier when evaluating the info series, not just when selecting it. +load 1m + metric{instance="a", job="1"} 1 2 3 4 5 6 7 8 + target_info{instance="a", job="1", version="v1"} 1 + +# The enrichment is evaluated as of t=0 (the @ timestamp) at every step, independent of the +# query range start: the two queries below agree on the shared timestamps 6m and 7m. +eval range from 4m to 7m step 1m info(metric @ 0) + metric{instance="a", job="1", version="v1"} 1 1 1 1 + +eval range from 6m to 7m step 1m info(metric @ 0) + metric{instance="a", job="1", version="v1"} 1 1 + +# The same holds for an instant query far past the @ timestamp: enrichment is pinned to t=0 +# rather than being looked up (and lost) at the evaluation time. +eval instant at 40m info(metric @ 0) + metric{instance="a", job="1", version="v1"} 1 + +clear + +# Churning target_info series: @ and offset pin which info series enriches, not just whether +# one is found. +load 1m + metric{instance="a", job="1"} 0 1 2 3 4 5 6 7 8 + target_info{instance="a", job="1", version="old"} 1 1 1 stale + target_info{instance="a", job="1", version="new"} _ _ _ 1 1 1 1 1 1 + +# The info series is matched as of ts-2m, like the base samples, so enrichment reflects the +# version current at the offset-shifted time and switches when that time crosses the flip at 3m. +eval range from 4m to 8m step 1m info(metric offset 2m) + metric{instance="a", job="1", version="old"} 2 _ _ _ _ + metric{instance="a", job="1", version="new"} _ 3 4 5 6 + +# The @ timestamp selects the version current at 2m, even at evaluation times where "new" is +# current and "old" has gone stale. +eval range from 8m to 9m step 1m info(metric @ 120) + metric{instance="a", job="1", version="old"} 2 2 + +# @ on a subquery argument is honoured too: enrichment is as of the subquery's @ timestamp. +eval instant at 40m info(last_over_time(metric[10m:1m] @ 420)) + metric{instance="a", job="1", version="new"} 7 + +# An offset inside a pinned subquery shifts the info series reference time as well: samples +# are read as of 2m (@ 3m minus the 1m offset), when "old" was still current. +eval instant at 40m info(last_over_time((metric offset 1m)[10m:1m] @ 180)) + metric{instance="a", job="1", version="old"} 2 + +# Without @, a subquery offset shifts the info series reference time per step. +eval range from 8m to 9m step 1m info(last_over_time(metric[5m:1m] offset 6m)) + metric{instance="a", job="1", version="old"} 2 _ + metric{instance="a", job="1", version="new"} _ 3 + clear # info_metric churn: diff --git a/rules/group.go b/rules/group.go index 704fd13d850..236289b6edc 100644 --- a/rules/group.go +++ b/rules/group.go @@ -116,6 +116,7 @@ func NewGroup(o GroupOptions) *Group { metrics.GroupLastRuleDurationSum.WithLabelValues(key) metrics.GroupRules.WithLabelValues(key).Set(float64(len(o.Rules))) metrics.GroupSamples.WithLabelValues(key) + metrics.RulesSkipped.WithLabelValues(key) metrics.GroupInterval.WithLabelValues(key).Set(o.Interval.Seconds()) evalIterationFunc := o.EvalIterationFunc @@ -512,6 +513,13 @@ func (g *Group) Eval(ctx context.Context, ts time.Time) { } logger := g.logger.With("name", rule.Name(), "index", i) + if _, isAlert := rule.(*AlertingRule); !isAlert { + if g.opts.MemoryLimiter != nil && !g.opts.MemoryLimiter.AllowRecordingRules() { + g.metrics.RulesSkipped.WithLabelValues(GroupKey(g.File(), g.Name())).Inc() + return + } + } + ctx, sp := otel.Tracer("").Start(ctx, "rule") sp.SetAttributes(attribute.String("name", rule.Name())) defer func(t time.Time) { @@ -926,6 +934,7 @@ type Metrics struct { GroupLastRestoreDuration *prometheus.GaugeVec GroupRules *prometheus.GaugeVec GroupSamples *prometheus.GaugeVec + RulesSkipped *prometheus.CounterVec } // NewGroupMetrics creates a new instance of Metrics and registers it with the provided registerer, @@ -1051,6 +1060,14 @@ func NewGroupMetrics(reg prometheus.Registerer) *Metrics { }, []string{"rule_group"}, ), + RulesSkipped: prometheus.NewCounterVec( + prometheus.CounterOpts{ + Namespace: namespace, + Name: "rule_evaluations_skipped_total", + Help: "The total number of rule evaluations skipped due to memory limit.", + }, + []string{"rule_group"}, + ), } if reg != nil { @@ -1070,6 +1087,7 @@ func NewGroupMetrics(reg prometheus.Registerer) *Metrics { m.GroupLastRestoreDuration, m.GroupRules, m.GroupSamples, + m.RulesSkipped, ) } diff --git a/rules/manager.go b/rules/manager.go index 3fba38b4bb3..06c9d6fd550 100644 --- a/rules/manager.go +++ b/rules/manager.go @@ -38,6 +38,7 @@ import ( "github.com/prometheus/prometheus/promql/parser" "github.com/prometheus/prometheus/storage" "github.com/prometheus/prometheus/util/features" + "github.com/prometheus/prometheus/util/memorylimiter" "github.com/prometheus/prometheus/util/strutil" ) @@ -143,6 +144,9 @@ type ManagerOptions struct { // Parser is the PromQL parser used for parsing rule expressions. Parser parser.Parser + + // MemoryLimiter is used to skip recording rules evaluation under memory pressure. + MemoryLimiter memorylimiter.MemoryLimiter } // NewManager returns an implementation of Manager, ready to be started diff --git a/rules/manager_test.go b/rules/manager_test.go index 2e3ccf781c6..14aabaed252 100644 --- a/rules/manager_test.go +++ b/rules/manager_test.go @@ -38,6 +38,7 @@ import ( "go.uber.org/atomic" "go.yaml.in/yaml/v2" + "github.com/prometheus/prometheus/config" "github.com/prometheus/prometheus/model/labels" "github.com/prometheus/prometheus/model/rulefmt" "github.com/prometheus/prometheus/model/timestamp" @@ -49,6 +50,7 @@ import ( "github.com/prometheus/prometheus/tsdb" "github.com/prometheus/prometheus/tsdb/chunkenc" "github.com/prometheus/prometheus/tsdb/tsdbutil" + "github.com/prometheus/prometheus/util/memorylimiter" "github.com/prometheus/prometheus/util/stats" "github.com/prometheus/prometheus/util/teststorage" prom_testutil "github.com/prometheus/prometheus/util/testutil" @@ -2808,3 +2810,73 @@ func (*closeCountingQuery) Statement() parser.Statement { return nil } func (*closeCountingQuery) Stats() *stats.Statistics { return nil } func (*closeCountingQuery) Cancel() {} func (*closeCountingQuery) String() string { return "" } + +type mockRuleMemoryLimiter struct { + allowRecordingRules bool +} + +func (*mockRuleMemoryLimiter) State() memorylimiter.LimiterState { + return memorylimiter.StateHardLimit +} +func (*mockRuleMemoryLimiter) AllowScrape() bool { return true } +func (*mockRuleMemoryLimiter) AllowOTLP() bool { return true } +func (*mockRuleMemoryLimiter) AllowRemoteWrite() bool { return true } +func (*mockRuleMemoryLimiter) AllowRemoteRead() bool { return true } +func (*mockRuleMemoryLimiter) AllowFederation() bool { return true } +func (m *mockRuleMemoryLimiter) AllowRecordingRules() bool { return m.allowRecordingRules } +func (*mockRuleMemoryLimiter) ApplyConfig(*config.MemoryLimiterConfig) error { return nil } +func (*mockRuleMemoryLimiter) Start(context.Context) {} +func (*mockRuleMemoryLimiter) Stop() {} + +func TestGroup_MemoryLimiterRecordingRuleSkipping(t *testing.T) { + storage := teststorage.New(t) + defer storage.Close() + + var alertFired atomic.Bool + notifyFunc := func(_ context.Context, _ string, _ ...*Alert) { + alertFired.Store(true) + } + + queryFunc := func(_ context.Context, _ string, ts time.Time) (promql.Vector, error) { + return promql.Vector{ + promql.Sample{ + Metric: labels.FromStrings("__name__", "up", "job", "test"), + T: ts.UnixMilli(), + F: 1, + }, + }, nil + } + + opts := &ManagerOptions{ + Appendable: storage, + QueryFunc: queryFunc, + NotifyFunc: notifyFunc, + Context: context.Background(), + Logger: promslog.NewNopLogger(), + MemoryLimiter: &mockRuleMemoryLimiter{allowRecordingRules: false}, + Metrics: NewGroupMetrics(prometheus.NewRegistry()), + } + + parsedExpr, err := testParser.ParseExpr("up == 1") + require.NoError(t, err) + + recRule := NewRecordingRule("job:up:count", parsedExpr, labels.EmptyLabels()) + alertRule := NewAlertingRule("InstanceUp", parsedExpr, time.Second, 0, labels.EmptyLabels(), labels.EmptyLabels(), labels.EmptyLabels(), "", true, promslog.NewNopLogger()) + + group := NewGroup(GroupOptions{ + Name: "test_group", + File: "test_file.yml", + Interval: time.Minute, + Rules: []Rule{recRule, alertRule}, + Opts: opts, + }) + + // Run single evaluation cycle. + group.Eval(context.Background(), time.Now()) + + // 1. Verify recording rule was skipped (RulesSkipped incremented, no sample persisted). + require.Equal(t, float64(1), testutil.ToFloat64(opts.Metrics.RulesSkipped.WithLabelValues(GroupKey("test_file.yml", "test_group")))) + + // 2. Verify alerting rule in the SAME group was NOT skipped and fired alerts. + require.True(t, alertFired.Load(), "Alerting rule should be evaluated even when recording rule is skipped") +} diff --git a/scrape/manager.go b/scrape/manager.go index 55a4e11cdd3..6e427db3d14 100644 --- a/scrape/manager.go +++ b/scrape/manager.go @@ -36,6 +36,7 @@ import ( "github.com/prometheus/prometheus/storage" "github.com/prometheus/prometheus/util/features" "github.com/prometheus/prometheus/util/logging" + "github.com/prometheus/prometheus/util/memorylimiter" "github.com/prometheus/prometheus/util/osutil" "github.com/prometheus/prometheus/util/pool" ) @@ -178,6 +179,9 @@ type Options struct { // because of an early startup scrape. InitialScrapeOffset time.Duration + // Optional memory limiter to abort scrapes under memory pressure. + MemoryLimiter memorylimiter.MemoryLimiter + // private option for testability. skipJitterOffsetting bool } diff --git a/scrape/metrics.go b/scrape/metrics.go index 34f1e28dbab..a42a7f85fa5 100644 --- a/scrape/metrics.go +++ b/scrape/metrics.go @@ -57,6 +57,7 @@ type scrapeMetrics struct { targetScrapePoolExceededLabelLimits prometheus.Counter targetScrapeNativeHistogramBucketLimit prometheus.Counter targetScrapeDuration prometheus.Histogram + targetScrapesSkipped prometheus.Counter } func newScrapeMetrics(reg prometheus.Registerer) (*scrapeMetrics, error) { @@ -263,6 +264,13 @@ func newScrapeMetrics(reg prometheus.Registerer) (*scrapeMetrics, error) { }, ) + sm.targetScrapesSkipped = prometheus.NewCounter( + prometheus.CounterOpts{ + Name: "prometheus_target_scrapes_exceeded_memory_limit_total", + Help: "Total number of target scrapes skipped due to memory limits.", + }, + ) + for _, collector := range []prometheus.Collector{ // Used by Manager. sm.targetMetadataCache, @@ -295,6 +303,7 @@ func newScrapeMetrics(reg prometheus.Registerer) (*scrapeMetrics, error) { sm.targetScrapePoolExceededLabelLimits, sm.targetScrapeNativeHistogramBucketLimit, sm.targetScrapeDuration, + sm.targetScrapesSkipped, } { err := reg.Register(collector) if err != nil { @@ -336,6 +345,7 @@ func (sm *scrapeMetrics) Unregister() { sm.reg.Unregister(sm.targetScrapePoolExceededLabelLimits) sm.reg.Unregister(sm.targetScrapeNativeHistogramBucketLimit) sm.reg.Unregister(sm.targetScrapeDuration) + sm.reg.Unregister(sm.targetScrapesSkipped) } type TargetsGatherer interface { diff --git a/scrape/scrape.go b/scrape/scrape.go index 5e4bde470f0..52925ec1f06 100644 --- a/scrape/scrape.go +++ b/scrape/scrape.go @@ -56,6 +56,7 @@ import ( "github.com/prometheus/prometheus/model/value" "github.com/prometheus/prometheus/storage" "github.com/prometheus/prometheus/util/logging" + "github.com/prometheus/prometheus/util/memorylimiter" "github.com/prometheus/prometheus/util/pool" ) @@ -698,7 +699,10 @@ type targetScraper struct { metrics *scrapeMetrics } -var errBodySizeLimit = errors.New("body size limit exceeded") +var ( + errBodySizeLimit = errors.New("body size limit exceeded") + errScrapeMemoryLimitExceeded = errors.New("memory limit exceeded") +) // acceptHeader transforms preference from the options into specific header values as // https://www.rfc-editor.org/rfc/rfc9110.html#name-accept defines. @@ -884,6 +888,7 @@ type scrapeLoop struct { skipJitterOffsetting bool // For testability. scrapeOnShutdown bool initialScrapeOffset time.Duration + memoryLimiter memorylimiter.MemoryLimiter // error injection through setForcedError. forcedErr error forcedErrMtx sync.Mutex @@ -1241,6 +1246,7 @@ func newScrapeLoop(opts scrapeLoopOptions) *scrapeLoop { skipJitterOffsetting: opts.sp.options.skipJitterOffsetting, scrapeOnShutdown: opts.sp.options.ScrapeOnShutdown, initialScrapeOffset: opts.sp.options.InitialScrapeOffset, + memoryLimiter: opts.sp.options.MemoryLimiter, } } @@ -1360,6 +1366,20 @@ func (sl *scrapeLoop) scrapeAndReport(last, appendTime time.Time, errc chan<- er var total, added, seriesAdded, bytesRead int var err, appErr, scrapeErr error + // Check if scrape is allowed by memory limiter. + if sl.memoryLimiter != nil && !sl.memoryLimiter.AllowScrape() { + sl.metrics.targetScrapesSkipped.Inc() + scrapeErr = errScrapeMemoryLimitExceeded + sl.scraper.Report(start, 0, scrapeErr) + if errc != nil { + select { + case errc <- scrapeErr: + case <-sl.ctx.Done(): + } + } + return start + } + app := sl.appender() defer func() { if err != nil { diff --git a/scrape/scrape_test.go b/scrape/scrape_test.go index cff67edc0f1..7e95459dfc2 100644 --- a/scrape/scrape_test.go +++ b/scrape/scrape_test.go @@ -71,6 +71,7 @@ import ( "github.com/prometheus/prometheus/storage" "github.com/prometheus/prometheus/tsdb" "github.com/prometheus/prometheus/tsdb/chunkenc" + "github.com/prometheus/prometheus/util/memorylimiter" "github.com/prometheus/prometheus/util/pool" "github.com/prometheus/prometheus/util/teststorage" "github.com/prometheus/prometheus/util/testutil" @@ -7962,3 +7963,88 @@ func TestScrapeOffsetDistribution(t *testing.T) { } }) } + +type mockMemoryLimiter struct { + allowScrape bool +} + +func (m *mockMemoryLimiter) State() memorylimiter.LimiterState { + if m.allowScrape { + return memorylimiter.StateOK + } + return memorylimiter.StateHardLimit +} +func (m *mockMemoryLimiter) AllowScrape() bool { return m.allowScrape } +func (m *mockMemoryLimiter) AllowOTLP() bool { return m.allowScrape } +func (m *mockMemoryLimiter) AllowRemoteWrite() bool { return m.allowScrape } +func (m *mockMemoryLimiter) AllowRemoteRead() bool { return m.allowScrape } +func (m *mockMemoryLimiter) AllowFederation() bool { return m.allowScrape } +func (m *mockMemoryLimiter) AllowRecordingRules() bool { return m.allowScrape } +func (*mockMemoryLimiter) ApplyConfig(*config.MemoryLimiterConfig) error { return nil } +func (*mockMemoryLimiter) Start(context.Context) {} +func (*mockMemoryLimiter) Stop() {} + +func TestScrapeLoop_MemoryLimiterAbort(t *testing.T) { + for _, appV2 := range []bool{false, true} { + t.Run(fmt.Sprintf("appV2=%t", appV2), func(t *testing.T) { + s := teststorage.New(t) + defer s.Close() + + limiter := &mockMemoryLimiter{allowScrape: false} + sa := selectAppendable(s, appV2) + metrics := newTestScrapeMetrics(t) + cfg := &config.ScrapeConfig{ + JobName: "test", + ScrapeInterval: model.Duration(100 * time.Millisecond), + ScrapeTimeout: model.Duration(100 * time.Millisecond), + MetricNameValidationScheme: model.UTF8Validation, + MetricNameEscapingScheme: model.AllowUTF8, + } + sp, err := newScrapePool( + cfg, + sa.V1(), + sa.V2(), + 0, + nil, + nil, + &Options{MemoryLimiter: limiter}, + metrics, + ) + require.NoError(t, err) + defer sp.stop() + + target := NewTarget(labels.FromStrings(model.AddressLabel, "localhost:9090"), cfg, nil, nil) + scraper := &testScraper{} + sl := newScrapeLoop(scrapeLoopOptions{ + target: target, + scraper: scraper, + cache: newScrapeCache(metrics), + interval: 100 * time.Millisecond, + timeout: 100 * time.Millisecond, + sp: sp, + }) + + errc := make(chan error, 1) + sl.scrapeAndReport(time.Time{}, time.Now(), errc) + + select { + case err := <-errc: + require.Equal(t, errScrapeMemoryLimitExceeded, err) + default: + t.Fatal("expected errScrapeMemoryLimitExceeded") + } + + require.Equal(t, errScrapeMemoryLimitExceeded, scraper.lastError) + + // Verify that targetScrapesSkipped metric was incremented. + require.Equal(t, float64(1), prom_testutil.ToFloat64(metrics.targetScrapesSkipped)) + + // Query storage to assert 0 samples were appended (NO up=0 sample in storage!). + q, err := s.Querier(0, time.Now().UnixNano()) + require.NoError(t, err) + defer q.Close() + seriesSet := q.Select(t.Context(), false, nil, labels.MustNewMatcher(labels.MatchEqual, "__name__", "up")) + require.False(t, seriesSet.Next(), "expected no series appended to storage on memory limiter abort") + }) + } +} diff --git a/storage/remote/otlptranslator/prometheusremotewrite/metrics_to_prw.go b/storage/remote/otlptranslator/prometheusremotewrite/metrics_to_prw.go index 86847860d1e..ef558a2372d 100644 --- a/storage/remote/otlptranslator/prometheusremotewrite/metrics_to_prw.go +++ b/storage/remote/otlptranslator/prometheusremotewrite/metrics_to_prw.go @@ -137,12 +137,41 @@ type targetInfoKey struct { timestamp int64 } +const maxSanitizedLabels = 64 + func NewPrometheusConverter(appender storage.AppenderV2) *PrometheusConverter { - return &PrometheusConverter{ - scratchBuilder: labels.NewScratchBuilder(0), - builder: labels.NewBuilder(labels.EmptyLabels()), + c := &PrometheusConverter{} + c.Reset(appender) + return c +} + +// Reset prepares c for conversion with appender. It must only be called after +// Commit or Rollback has completed on the previous appender. Passing nil clears +// request-local references before c is returned to a pool. +func (c *PrometheusConverter) Reset(appender storage.AppenderV2) { + sanitizedLabels := c.sanitizedLabels + if len(sanitizedLabels) > maxSanitizedLabels { + sanitizedLabels = nil + } else { + clear(sanitizedLabels) + } + + // Preserve only the bounded label cache across requests. + *c = PrometheusConverter{ appender: appender, - sanitizedLabels: make(map[string]string, 64), // Pre-size for typical label count. + sanitizedLabels: sanitizedLabels, + } + + if appender == nil { + return + } + + // Builders retain their input strings in backing arrays after Reset, so use + // fresh builders for every request. + c.scratchBuilder = labels.NewScratchBuilder(0) + c.builder = labels.NewBuilder(labels.EmptyLabels()) + if c.sanitizedLabels == nil { + c.sanitizedLabels = make(map[string]string, maxSanitizedLabels) } } diff --git a/storage/remote/otlptranslator/prometheusremotewrite/metrics_to_prw_test.go b/storage/remote/otlptranslator/prometheusremotewrite/metrics_to_prw_test.go index 6bbb829e485..ee1b080e3f9 100644 --- a/storage/remote/otlptranslator/prometheusremotewrite/metrics_to_prw_test.go +++ b/storage/remote/otlptranslator/prometheusremotewrite/metrics_to_prw_test.go @@ -18,6 +18,7 @@ package prometheusremotewrite import ( "context" + "errors" "fmt" "testing" "time" @@ -34,9 +35,100 @@ import ( "github.com/prometheus/prometheus/model/labels" "github.com/prometheus/prometheus/model/metadata" "github.com/prometheus/prometheus/storage" + "github.com/prometheus/prometheus/util/annotations" "github.com/prometheus/prometheus/util/teststorage" ) +func TestPrometheusConverter_Reset(t *testing.T) { + t.Run("isolates requests", func(t *testing.T) { + request := pmetricotlp.NewExportRequest() + metrics := request.Metrics().ResourceMetrics().AppendEmpty().ScopeMetrics().AppendEmpty().Metrics() + metric := metrics.AppendEmpty() + metric.SetName("test_gauge") + dataPoint := metric.SetEmptyGauge().DataPoints().AppendEmpty() + dataPoint.SetTimestamp(pcommon.NewTimestampFromTime(time.Unix(0, 0))) + dataPoint.SetIntValue(1) + dataPoint.Attributes().PutStr("foo.bar", "value") + + converter := NewPrometheusConverter(nil) + for _, tc := range []struct { + name string + allowUTF8 bool + labelName string + otherLabelName string + }{ + { + name: "escaped labels", + labelName: "foo_bar", + otherLabelName: "foo.bar", + }, + { + name: "UTF-8 labels", + allowUTF8: true, + labelName: "foo.bar", + otherLabelName: "foo_bar", + }, + } { + t.Run(tc.name, func(t *testing.T) { + appendable := teststorage.NewAppendable() + appender := appendable.AppenderV2(t.Context()) + converter.Reset(appender) + + annots, err := converter.FromMetrics(t.Context(), request.Metrics(), Settings{ + AllowUTF8: tc.allowUTF8, + DisableTargetInfo: true, + }) + require.NoError(t, err) + require.Empty(t, annots) + require.NoError(t, appender.Commit()) + + samples := appendable.ResultSamples() + require.Len(t, samples, 1) + require.Equal(t, "value", samples[0].L.Get(tc.labelName)) + require.False(t, samples[0].L.Has(tc.otherLabelName)) + + converter.Reset(nil) + }) + } + }) + + t.Run("clears request state", func(t *testing.T) { + converter := NewPrometheusConverter(&noOpAppender{}) + converter.everyN = everyNTimes{n: 128, i: 1, err: context.Canceled} + converter.scratchBuilder.Add("request_label", "request_value") + converter.builder.Set("request_label", "request_value") + converter.seenTargetInfo = map[targetInfoKey]struct{}{{}: {}} + converter.resourceLabels = &cachedResourceLabels{jobLabel: "request_job"} + converter.scopeLabels = &cachedScopeLabels{scopeName: "request_scope"} + converter.labelNamer = otlptranslator.LabelNamer{UTF8Allowed: true} + converter.sanitizedLabels["request_label"] = "request_label" + converter.collisionAnnots = annotations.Annotations{"request": errors.New("request annotation")} + converter.recordedCollisions = map[string]struct{}{"request_label": {}} + converter.collisionSource = collisionFromResource + + converter.Reset(nil) + + require.Equal(t, PrometheusConverter{ + sanitizedLabels: map[string]string{}, + }, *converter) + }) + + t.Run("drops large label cache", func(t *testing.T) { + converter := NewPrometheusConverter(&noOpAppender{}) + for i := range maxSanitizedLabels + 1 { + label := fmt.Sprintf("request_label_%d", i) + converter.sanitizedLabels[label] = label + } + + converter.Reset(nil) + require.Nil(t, converter.sanitizedLabels) + + converter.Reset(&noOpAppender{}) + require.NotNil(t, converter.sanitizedLabels) + require.Empty(t, converter.sanitizedLabels) + }) +} + func TestFromMetrics(t *testing.T) { t.Run("Successful", func(t *testing.T) { for _, tc := range []struct { diff --git a/storage/remote/write_otlp_handler.go b/storage/remote/write_otlp_handler.go index 6c014d9e88e..7ce5d69dda1 100644 --- a/storage/remote/write_otlp_handler.go +++ b/storage/remote/write_otlp_handler.go @@ -19,6 +19,7 @@ import ( "fmt" "log/slog" "net/http" + "sync" "time" deltatocumulative "github.com/open-telemetry/opentelemetry-collector-contrib/processor/deltatocumulativeprocessor" @@ -67,6 +68,11 @@ func NewOTLPWriteHandler(logger *slog.Logger, reg prometheus.Registerer, appenda allowDeltaTemporality: opts.NativeDelta, lookbackDelta: opts.LookbackDelta, enableTypeAndUnitLabels: opts.EnableTypeAndUnitLabels, + converterPool: sync.Pool{ + New: func() any { + return otlptranslator.NewPrometheusConverter(nil) + }, + }, translationWarnings: promauto.With(reg).NewCounterVec(prometheus.CounterOpts{ Namespace: "prometheus", Subsystem: "api", @@ -113,6 +119,7 @@ type rwExporter struct { lookbackDelta time.Duration enableTypeAndUnitLabels bool translationWarnings *prometheus.CounterVec + converterPool sync.Pool } func (rw *rwExporter) ConsumeMetrics(ctx context.Context, md pmetric.Metrics) error { @@ -121,7 +128,8 @@ func (rw *rwExporter) ConsumeMetrics(ctx context.Context, md pmetric.Metrics) er AppenderV2: rw.appendable.AppenderV2(ctx), maxTime: timestamp.FromTime(time.Now().Add(maxAheadTime)), } - converter := otlptranslator.NewPrometheusConverter(app) + converter := rw.converterPool.Get().(*otlptranslator.PrometheusConverter) + converter.Reset(app) annots, err := converter.FromMetrics(ctx, md, otlptranslator.Settings{ AddMetricSuffixes: otlpCfg.TranslationStrategy.ShouldAddSuffixes(), AllowUTF8: !otlpCfg.TranslationStrategy.ShouldEscape(), @@ -139,9 +147,11 @@ func (rw *rwExporter) ConsumeMetrics(ctx context.Context, md pmetric.Metrics) er defer func() { if err != nil { _ = app.Rollback() - return + } else { + err = app.Commit() } - err = app.Commit() + converter.Reset(nil) + rw.converterPool.Put(converter) }() ws, _ := annots.AsStrings("", 0, 0) if len(ws) > 0 { diff --git a/storage/remote/write_otlp_handler_test.go b/storage/remote/write_otlp_handler_test.go index 621b8687120..adfa7ac4aea 100644 --- a/storage/remote/write_otlp_handler_test.go +++ b/storage/remote/write_otlp_handler_test.go @@ -15,6 +15,7 @@ package remote import ( "bytes" + "context" "errors" "fmt" "log/slog" @@ -25,6 +26,7 @@ import ( "reflect" "runtime" "strconv" + "sync" "testing" "time" @@ -335,6 +337,27 @@ func TestOTLPWriteHandler(t *testing.T) { require.Len(t, samples, 1) require.Equal(t, "healthy_metric", samples[0].L.Get(labels.MetricName)) }) + + t.Run("concurrent requests", func(t *testing.T) { + handler, payload := newOTLPWriteHandlerFixture(t) + + const requests = 64 + statuses := make(chan int, requests) + var wg sync.WaitGroup + for range requests { + wg.Go(func() { + recorder := httptest.NewRecorder() + handler.ServeHTTP(recorder, newOTLPWriteHandlerRequest(payload)) + statuses <- recorder.Code + }) + } + wg.Wait() + close(statuses) + + for status := range statuses { + require.Equal(t, http.StatusOK, status) + } + }) } func handleOTLP(t *testing.T, exportRequest pmetricotlp.ExportRequest, otlpCfg config.OTLPConfig, otlpOpts OTLPOptions) *teststorage.Appendable { @@ -500,6 +523,85 @@ func TestOTLPDelta(t *testing.T) { } } +// BenchmarkOTLPWriteHandler measures a decoded OTLP request through the HTTP +// handler, translation, and appender commit paths. The appendable discards +// samples so that the benchmark does not retain prior requests. +func BenchmarkOTLPWriteHandler(b *testing.B) { + handler, payload := newOTLPWriteHandlerFixture(b) + + b.Run("serial", func(b *testing.B) { + b.ReportAllocs() + for b.Loop() { + recorder := httptest.NewRecorder() + handler.ServeHTTP(recorder, newOTLPWriteHandlerRequest(payload)) + if recorder.Code != http.StatusOK { + b.Fatalf("unexpected status code %d", recorder.Code) + } + } + }) + + b.Run("parallel", func(b *testing.B) { + b.ReportAllocs() + b.RunParallel(func(pb *testing.PB) { + for pb.Next() { + recorder := httptest.NewRecorder() + handler.ServeHTTP(recorder, newOTLPWriteHandlerRequest(payload)) + if recorder.Code != http.StatusOK { + b.Errorf("unexpected status code %d", recorder.Code) + return + } + } + }) + }) +} + +func newOTLPWriteHandlerFixture(tb testing.TB) (http.Handler, []byte) { + tb.Helper() + + request := generateOTLPWriteRequest(time.Unix(0, 0), time.Unix(0, 0)) + payload, err := request.MarshalProto() + require.NoError(tb, err) + + handler := NewOTLPWriteHandler( + slog.New(slog.DiscardHandler), + nil, + discardAppendable{}, + func() config.Config { return config.Config{OTLPConfig: config.DefaultOTLPConfig} }, + OTLPOptions{}, + ) + return handler, payload +} + +func newOTLPWriteHandlerRequest(payload []byte) *http.Request { + req := httptest.NewRequest(http.MethodPost, "/", bytes.NewReader(payload)) + req.Header.Set("Content-Type", pbContentType) + return req +} + +type discardAppendable struct{} + +var _ storage.AppendableV2 = discardAppendable{} + +func (discardAppendable) AppenderV2(context.Context) storage.AppenderV2 { + return discardAppender{} +} + +type discardAppender struct{} + +var _ storage.AppenderV2 = discardAppender{} + +func (discardAppender) Append(storage.SeriesRef, labels.Labels, int64, int64, float64, *histogram.Histogram, *histogram.FloatHistogram, storage.AOptions) (storage.SeriesRef, error) { + return 0, nil +} + +func (discardAppender) Commit() error { + return nil +} + +func (discardAppender) Rollback() error { + return nil +} + func BenchmarkOTLP(b *testing.B) { start := time.Date(2000, 1, 2, 3, 4, 5, 0, time.UTC) diff --git a/tsdb/chunks/chunks.go b/tsdb/chunks/chunks.go index b15b93d3162..d2d63812d59 100644 --- a/tsdb/chunks/chunks.go +++ b/tsdb/chunks/chunks.go @@ -76,7 +76,10 @@ func (p HeadChunkRef) Unpack() (HeadSeriesRef, HeadChunkID) { } // HeadChunkID refers to a specific chunk in a series (memSeries) in the Head. -// Each memSeries has its own monotonically increasing number to refer to its chunks. +// Each memSeries has its own number to refer to its chunks: it is monotonically +// increasing for in-order chunks, while out-of-order chunk IDs wrap around modulo +// 2^23 (see oooHeadChunkID in tsdb/head_read.go), so they only increase between +// wrap-arounds. // If the HeadChunkID value is... // - memSeries.firstChunkID+len(memSeries.mmappedChunks), it's the head chunk. // - less than the above, but >= memSeries.firstID, then it's diff --git a/tsdb/db_test.go b/tsdb/db_test.go index 25eafec065f..def826c3d82 100644 --- a/tsdb/db_test.go +++ b/tsdb/db_test.go @@ -11563,3 +11563,68 @@ func TestBeyondSizeRetentionWithPercentage(t *testing.T) { require.Len(t, deletable, 1) require.Contains(t, deletable, ulid) } + +func TestOOOCompactionAcrossChunkIDWrap(t *testing.T) { + for name, scenario := range sampleTypeScenarios { + t.Run(name, func(t *testing.T) { + testOOOCompactionAcrossChunkIDWrap(t, scenario) + }) + } +} + +func testOOOCompactionAcrossChunkIDWrap(t *testing.T, scenario sampleTypeScenario) { + opts := DefaultOptions() + opts.OutOfOrderCapMax = 5 + opts.OutOfOrderTimeWindow = 4 * time.Hour.Milliseconds() + + db := newTestDB(t, withOpts(opts)) + db.DisableCompactions() + + l := labels.FromStrings("l", "v1") + minutes := func(m int64) int64 { return m * time.Minute.Milliseconds() } + + app := db.Appender(context.Background()) + + // In-order sample. + ref, _, err := scenario.appendFunc(app, l, minutes(200), 200) + require.NoError(t, err) + var expSamples []chunks.Sample + expSamples = append(expSamples, scenario.sampleFunc(minutes(200), 200)) + + // 15 OOO samples to create 3 mmapped chunks (cap=5). + for i := int64(1); i <= 15; i++ { + _, _, err = scenario.appendFunc(app, l, minutes(i), i) + require.NoError(t, err) + expSamples = append(expSamples, scenario.sampleFunc(minutes(i), i)) + } + require.NoError(t, app.Commit()) + + // Seed firstOOOChunkID near the wrap boundary. + ms := db.head.series.getByID(chunks.HeadSeriesRef(ref)) + require.NotNil(t, ms) + ms.Lock() + require.NotNil(t, ms.ooo) + ms.ooo.firstOOOChunkID = chunks.HeadChunkID(oooChunkIDMask - 1) + ms.Unlock() + + // More OOO data whose chunk IDs cross the boundary. + app = db.Appender(context.Background()) + for i := int64(16); i <= 30; i++ { + _, _, err = scenario.appendFunc(app, l, minutes(i), i) + require.NoError(t, err) + expSamples = append(expSamples, scenario.sampleFunc(minutes(i), i)) + } + require.NoError(t, app.Commit()) + + // Compact. + require.NoError(t, db.Compact(context.Background())) + + // Query and verify all data is present. + querier, err := db.Querier(0, minutes(300)) + require.NoError(t, err) + + seriesSet := query(t, querier, labels.MustNewMatcher(labels.MatchEqual, "l", "v1")) + + sort.Slice(expSamples, func(i, j int) bool { return expSamples[i].T() < expSamples[j].T() }) + requireEqualSeries(t, map[string][]chunks.Sample{l.String(): expSamples}, seriesSet, true) +} diff --git a/tsdb/head.go b/tsdb/head.go index ab2fff7cdeb..9f07d7df227 100644 --- a/tsdb/head.go +++ b/tsdb/head.go @@ -2920,7 +2920,7 @@ func (s *memSeries) truncateChunksBefore(mint int64, minOOOMmapRef chunks.ChunkD removedOOO = i + 1 } s.ooo.oooMmappedChunks = append(s.ooo.oooMmappedChunks[:0], s.ooo.oooMmappedChunks[removedOOO:]...) - s.ooo.firstOOOChunkID += chunks.HeadChunkID(removedOOO) + s.ooo.firstOOOChunkID = (s.ooo.firstOOOChunkID + chunks.HeadChunkID(removedOOO)) & (oooChunkIDMask - 1) if len(s.ooo.oooMmappedChunks) == 0 && s.ooo.oooHeadChunk == nil { s.ooo = nil diff --git a/tsdb/head_read.go b/tsdb/head_read.go index 97c0b42fe60..20cdf6ee156 100644 --- a/tsdb/head_read.go +++ b/tsdb/head_read.go @@ -417,8 +417,13 @@ const oooChunkIDMask = 1 << 23 // * 0 <= pos < len(s.oooMmappedChunks) refer to s.oooMmappedChunks[pos] // * pos == len(s.oooMmappedChunks) refers to s.oooHeadChunk // The caller must ensure that s.ooo is not nil. +// +// The position is wrapped modulo oooChunkIDMask so that firstOOOChunkID can +// grow indefinitely without overflowing the 23-bit ID space. Correctness +// requires len(oooMmappedChunks) to stay below oooChunkIDMask, which is +// enforced by the guard in mmapCurrentOOOHeadChunk. func (s *memSeries) oooHeadChunkID(pos int) chunks.HeadChunkID { - return (chunks.HeadChunkID(pos) + s.ooo.firstOOOChunkID) | oooChunkIDMask + return ((chunks.HeadChunkID(pos) + s.ooo.firstOOOChunkID) & (oooChunkIDMask - 1)) | oooChunkIDMask } func unpackHeadChunkRef(ref chunks.ChunkRef) (seriesID chunks.HeadSeriesRef, chunkID chunks.HeadChunkID, isOOO bool) { @@ -726,11 +731,13 @@ func (s *memSeries) chunk(id chunks.HeadChunkID, chunkDiskMapper *chunks.ChunkDi // oooChunk returns the chunk for the HeadChunkID by m-mapping it from the disk. // It never returns the head OOO chunk. func (s *memSeries) oooChunk(id chunks.HeadChunkID, chunkDiskMapper *chunks.ChunkDiskMapper, _ *sync.Pool) (chunk chunkenc.Chunk, maxTime int64, err error) { - // ix represents the index of chunk in the s.ooo.oooMmappedChunks slice. The chunk id's are - // incremented by 1 when new chunk is created, hence (id - firstOOOChunkID) gives the slice index. - ix := int(id) - int(s.ooo.firstOOOChunkID) + // ix represents the index of chunk in the s.ooo.oooMmappedChunks slice. + // Both id and firstOOOChunkID live in a modular 23-bit space; unsigned + // subtraction followed by masking recovers the correct index even when + // firstOOOChunkID has wrapped past 0. + ix := int((id - s.ooo.firstOOOChunkID) & (oooChunkIDMask - 1)) - if ix < 0 || ix >= len(s.ooo.oooMmappedChunks) { + if ix >= len(s.ooo.oooMmappedChunks) { return nil, 0, storage.ErrNotFound } diff --git a/tsdb/head_test.go b/tsdb/head_test.go index 1004b9eecab..7f0fa1a1e06 100644 --- a/tsdb/head_test.go +++ b/tsdb/head_test.go @@ -24,7 +24,6 @@ import ( "path" "path/filepath" "reflect" - "runtime" "slices" "sort" "strconv" @@ -1862,6 +1861,84 @@ func TestMemSeries_truncateChunks_scenarios(t *testing.T) { }) } +func TestOOOTruncateChunksBefore_Wrap(t *testing.T) { + tests := []struct { + name string + firstOOOChunkID chunks.HeadChunkID + numOOOChunks int + hasOOOHeadChunk bool + truncateN int + expFirstOOOChunkID chunks.HeadChunkID + expOOONil bool + expOOOMmappedLen int + }{ + { + name: "wrap past zero with remaining chunks", + firstOOOChunkID: chunks.HeadChunkID(oooChunkIDMask - 3), + numOOOChunks: 5, + truncateN: 4, + expFirstOOOChunkID: 1, + expOOOMmappedLen: 1, + }, + { + name: "truncate all OOO chunks, no head chunk, ooo becomes nil", + firstOOOChunkID: chunks.HeadChunkID(oooChunkIDMask - 3), + numOOOChunks: 5, + truncateN: 5, + expOOONil: true, + }, + { + name: "truncate all mmapped, head chunk keeps ooo alive", + firstOOOChunkID: chunks.HeadChunkID(oooChunkIDMask - 1), + numOOOChunks: 3, + hasOOOHeadChunk: true, + truncateN: 3, + expFirstOOOChunkID: 2, + expOOOMmappedLen: 0, + }, + } + + for _, tc := range tests { + t.Run(tc.name, func(t *testing.T) { + dir := t.TempDir() + chunkDiskMapper, err := chunks.NewChunkDiskMapper(nil, dir, chunkenc.NewPool(), chunks.DefaultWriteBufferSize, chunks.DefaultWriteQueueSize) + require.NoError(t, err) + t.Cleanup(func() { require.NoError(t, chunkDiskMapper.Close()) }) + + series := newMemSeries(labels.EmptyLabels(), 1, 0, true, false) + series.ooo = &memSeriesOOOFields{firstOOOChunkID: tc.firstOOOChunkID} + + refs := make([]chunks.ChunkDiskMapperRef, tc.numOOOChunks) + for i := 0; i < tc.numOOOChunks; i++ { + ref := chunkDiskMapper.WriteChunk(series.ref, int64(i*100), int64(i*100+99), chunkenc.NewXORChunk(), true, handleChunkWriteError) + refs[i] = ref + series.ooo.oooMmappedChunks = append(series.ooo.oooMmappedChunks, &mmappedChunk{ + ref: ref, minTime: int64(i * 100), maxTime: int64(i*100 + 99), + }) + } + + if tc.hasOOOHeadChunk { + series.ooo.oooHeadChunk = &oooHeadChunk{ + chunk: NewOOOChunk(), + minTime: int64(tc.numOOOChunks * 100), + maxTime: int64(tc.numOOOChunks*100 + 99), + } + } + + minOOOMmapRef := refs[tc.truncateN-1] + series.truncateChunksBefore(0, minOOOMmapRef) + + if tc.expOOONil { + require.Nil(t, series.ooo, "ooo should be nil after truncating all chunks") + } else { + require.NotNil(t, series.ooo, "ooo should not be nil") + require.Equal(t, tc.expFirstOOOChunkID, series.ooo.firstOOOChunkID, "firstOOOChunkID mismatch after wrap") + require.Len(t, series.ooo.oooMmappedChunks, tc.expOOOMmappedLen, "oooMmappedChunks length mismatch") + } + }) + } +} + func TestHeadDeleteSeriesWithoutSamples(t *testing.T) { for _, enableSTStorage := range []bool{false, true} { for _, compress := range []compression.Type{compression.None, compression.Snappy, compression.Zstd} { @@ -10007,10 +10084,6 @@ func TestHead_mmapHeadChunks(t *testing.T) { // the stripe and series locks, those locks must still be released. A leaked // lock previously self-deadlocked the subsequent Head.Close() -> mmapHeadChunks(). t.Run("panic releases locks", func(t *testing.T) { - if runtime.GOOS == "windows" { - t.Skip("forces a chunk-write failure by removing the open chunk directory, which Windows disallows while the ChunkDiskMapper holds the directory handle") - } - h, _ := newTestHead(t, DefaultBlockDuration, compression.None, false) require.NoError(t, h.Init(0)) @@ -10030,10 +10103,13 @@ func TestHead_mmapHeadChunks(t *testing.T) { require.NotNil(t, s) require.GreaterOrEqual(t, s.headChunkCount.Load(), uint32(2), "need >=2 head chunks pending mmap") - // Removing the chunk directory makes the next segment cut fail, so - // handleChunkWriteError panics inside mmapChunks. The chunk-write queue is - // synchronous by default, so the panic propagates out of mmapHeadChunks. - require.NoError(t, os.RemoveAll(mmappedChunksDir(h.opts.ChunkDirRoot))) + // Break the chunk write path in an OS agnostic way: dropping a segment + // file with a far higher sequence number into the head chunks directory + // makes the next cut file's sequence differ from the one the chunk + // reference was handed out for, which fails the write. + rogue := filepath.Join(mmappedChunksDir(h.opts.ChunkDirRoot), "000100") + require.NoError(t, os.WriteFile(rogue, nil, 0o666)) + // newTestHead's cleanup calls Head.Close() -> mmapHeadChunks(), which would // otherwise re-trigger the panic on the now-missing directory. Closing the // mapper first makes WriteChunk return ErrChunkDiskMapperClosed, which @@ -10436,3 +10512,156 @@ func TestHead_mmapHeadChunks(t *testing.T) { requireCounterConsistent("final state") }) } + +func TestQueryOOOHeadDuringTruncateAcrossWrap(t *testing.T) { + const maxT int64 = 6000 + + opts := DefaultOptions() + opts.OutOfOrderTimeWindow = maxT + opts.MinBlockDuration = maxT / 2 + + db := newTestDB(t, withOpts(opts)) + db.DisableCompactions() + + l := labels.FromStrings("a", "b") + app := db.Appender(context.Background()) + + // In-order samples. + ref, err := app.Append(0, l, 0, 0) + require.NoError(t, err) + for i := int64(100); i < maxT; i += 100 { + _, err = app.Append(ref, l, i, float64(i)) + require.NoError(t, err) + } + // OOO samples interleaved between in-order ones. + for i := int64(50); i < maxT; i += 100 { + _, err = app.Append(ref, l, i, float64(i)) + require.NoError(t, err) + } + require.NoError(t, app.Commit()) + + // Seed firstOOOChunkID near the wrap boundary. + ms := db.head.series.getByID(chunks.HeadSeriesRef(ref)) + require.NotNil(t, ms) + ms.Lock() + require.NotNil(t, ms.ooo) + ms.ooo.firstOOOChunkID = chunks.HeadChunkID(oooChunkIDMask - 1) + ms.Unlock() + + // Pre-truncation query. + q, err := db.Querier(0, maxT) + require.NoError(t, err) + ss := q.Select(context.Background(), false, nil, labels.MustNewMatcher(labels.MatchEqual, "a", "b")) + require.True(t, ss.Next()) + it := ss.At().Iterator(nil) + var preCount int + for it.Next() != chunkenc.ValNone { + preCount++ + } + require.NoError(t, it.Err()) + require.Positive(t, preCount, "pre-truncation query should return data") + require.NoError(t, q.Close()) + + // Compact, which triggers truncation and wraps firstOOOChunkID. + require.NoError(t, db.Compact(context.Background())) + + // Post-truncation query. + q, err = db.Querier(0, maxT) + require.NoError(t, err) + ss = q.Select(context.Background(), false, nil, labels.MustNewMatcher(labels.MatchEqual, "a", "b")) + require.True(t, ss.Next()) + it = ss.At().Iterator(nil) + var postCount int + for it.Next() != chunkenc.ValNone { + postCount++ + } + require.NoError(t, it.Err()) + require.Positive(t, postCount, "post-truncation query should return data") + require.NoError(t, q.Close()) +} + +func TestOOORestartResetsFirstOOOChunkID(t *testing.T) { + for name, scenario := range sampleTypeScenarios { + t.Run(name, func(t *testing.T) { + testOOORestartResetsFirstOOOChunkID(t, scenario) + }) + } +} + +func testOOORestartResetsFirstOOOChunkID(t *testing.T, scenario sampleTypeScenario) { + dir := t.TempDir() + wal, err := wlog.NewSize(nil, nil, filepath.Join(dir, "wal"), 32768, compression.Snappy) + require.NoError(t, err) + oooWlog, err := wlog.NewSize(nil, nil, filepath.Join(dir, wlog.WblDirName), 32768, compression.Snappy) + require.NoError(t, err) + + opts := DefaultHeadOptions() + opts.ChunkRange = 1000 + opts.ChunkDirRoot = dir + opts.OutOfOrderCapMax.Store(30) + opts.OutOfOrderTimeWindow.Store(1000 * time.Minute.Milliseconds()) + + h, err := NewHead(nil, nil, wal, oooWlog, opts, nil) + require.NoError(t, err) + require.NoError(t, h.Init(0)) + + l := labels.FromStrings("foo", "bar") + appendSample := func(mins int64) { + app := h.Appender(context.Background()) + _, _, err := scenario.appendFunc(app, l, mins*time.Minute.Milliseconds(), mins) + require.NoError(t, err) + require.NoError(t, app.Commit()) + } + + // In-order sample. + appendSample(200) + + // OOO samples: 92 samples to create 3 mmapped chunks (cap=30). + for mins := int64(100); mins <= 191; mins++ { + appendSample(mins) + } + + ms, ok, err := h.getOrCreate(l.Hash(), l, false) + require.NoError(t, err) + require.False(t, ok) + require.NotNil(t, ms) + require.NotNil(t, ms.ooo) + require.NotEmpty(t, ms.ooo.oooMmappedChunks) + + expMmapCount := len(ms.ooo.oooMmappedChunks) + + // Seed firstOOOChunkID to a large value. + ms.Lock() + ms.ooo.firstOOOChunkID = chunks.HeadChunkID(oooChunkIDMask - 100) + ms.Unlock() + + require.NoError(t, h.Close()) + + // Reopen. + wal, err = wlog.NewSize(nil, nil, filepath.Join(dir, "wal"), 32768, compression.Snappy) + require.NoError(t, err) + oooWlog, err = wlog.NewSize(nil, nil, filepath.Join(dir, wlog.WblDirName), 32768, compression.Snappy) + require.NoError(t, err) + h, err = NewHead(nil, nil, wal, oooWlog, opts, nil) + require.NoError(t, err) + require.NoError(t, h.Init(0)) + + ms, ok, err = h.getOrCreate(l.Hash(), l, false) + require.NoError(t, err) + require.False(t, ok) + require.NotNil(t, ms) + require.NotNil(t, ms.ooo) + + // firstOOOChunkID resets to 0 after replay. + require.Equal(t, chunks.HeadChunkID(0), ms.ooo.firstOOOChunkID) + + // Verify mmapped chunks are still accessible. + require.Len(t, ms.ooo.oooMmappedChunks, expMmapCount) + for _, m := range ms.ooo.oooMmappedChunks { + chk, err := h.chunkDiskMapper.Chunk(m.ref) + require.NoError(t, err) + require.Equal(t, int(m.numSamples), chk.NumSamples()) + } + + require.NoError(t, h.Close()) +} diff --git a/tsdb/ooo_head_read_test.go b/tsdb/ooo_head_read_test.go index 5dc1a4be14b..22c0910a03c 100644 --- a/tsdb/ooo_head_read_test.go +++ b/tsdb/ooo_head_read_test.go @@ -1267,3 +1267,151 @@ func TestNewOOOCompactionHead_panicReleasesLock(t *testing.T) { require.True(t, s.TryLock(), "series lock leaked after panic") s.Unlock() } + +func TestOOOQueryAcrossChunkIDWrap(t *testing.T) { + for name, scenario := range sampleTypeScenarios { + t.Run(name, func(t *testing.T) { + testOOOQueryAcrossChunkIDWrap(t, scenario) + }) + } +} + +func testOOOQueryAcrossChunkIDWrap(t *testing.T, scenario sampleTypeScenario) { + opts := DefaultOptions() + opts.OutOfOrderCapMax = 5 + opts.OutOfOrderTimeWindow = 120 * time.Minute.Milliseconds() + + db := newTestDB(t, withOpts(opts)) + + s1 := labels.FromStrings("l", "v1") + minutes := func(m int64) int64 { return m * time.Minute.Milliseconds() } + + app := db.Appender(context.Background()) + + // In-order sample to establish the series. + ref, _, err := scenario.appendFunc(app, s1, minutes(120), 120) + require.NoError(t, err) + var expSamples []chunks.Sample + expSamples = append(expSamples, scenario.sampleFunc(minutes(120), 120)) + + // First batch of 10 OOO samples (creates 2 mmapped OOO chunks with cap=5). + for i := int64(1); i <= 10; i++ { + _, _, err = scenario.appendFunc(app, s1, minutes(i), i) + require.NoError(t, err) + expSamples = append(expSamples, scenario.sampleFunc(minutes(i), i)) + } + require.NoError(t, app.Commit()) + + // Seed firstOOOChunkID near the wrap boundary. + ms := db.head.series.getByID(chunks.HeadSeriesRef(ref)) + require.NotNil(t, ms) + ms.Lock() + require.NotNil(t, ms.ooo) + ms.ooo.firstOOOChunkID = chunks.HeadChunkID(oooChunkIDMask - 1) + ms.Unlock() + + // Second batch of 10 OOO samples whose chunk IDs cross the boundary. + app = db.Appender(context.Background()) + for i := int64(11); i <= 20; i++ { + _, _, err = scenario.appendFunc(app, s1, minutes(i), i) + require.NoError(t, err) + expSamples = append(expSamples, scenario.sampleFunc(minutes(i), i)) + } + require.NoError(t, app.Commit()) + + // Query all data and verify every sample is returned. + querier, err := db.Querier(0, minutes(200)) + require.NoError(t, err) + + seriesSet := query(t, querier, labels.MustNewMatcher(labels.MatchEqual, "l", "v1")) + + sort.Slice(expSamples, func(i, j int) bool { return expSamples[i].T() < expSamples[j].T() }) + requireEqualSeries(t, map[string][]chunks.Sample{s1.String(): expSamples}, seriesSet, true) +} + +func TestOOOHeadChunkID_Wrap(t *testing.T) { + h, _ := newTestHead(t, 1000, compression.None, true) + require.NoError(t, h.Init(0)) + t.Cleanup(func() { require.NoError(t, h.Close()) }) + + s, _, _ := h.getOrCreate(1, labels.FromStrings("a", "b"), false) + s.ooo = &memSeriesOOOFields{firstOOOChunkID: chunks.HeadChunkID(oooChunkIDMask - 5)} + + for pos := 0; pos <= 10; pos++ { + id := s.oooHeadChunkID(pos) + expected := chunks.HeadChunkID((pos + oooChunkIDMask - 5) % oooChunkIDMask) + + require.NotZero(t, id&oooChunkIDMask, "pos %d: OOO flag (bit 23) must be set", pos) + require.Less(t, id, chunks.HeadChunkID(1<<24), "pos %d: chunk ID must fit in 24 bits", pos) + require.Equal(t, expected, id&(oooChunkIDMask-1), "pos %d: lower 23 bits mismatch", pos) + + ref := chunks.NewHeadChunkRef(s.ref, id) + _, chunkID, isOOO := unpackHeadChunkRef(chunks.ChunkRef(ref)) + require.True(t, isOOO, "pos %d: round-trip must identify as OOO", pos) + require.Equal(t, expected, chunkID, "pos %d: round-trip chunkID mismatch", pos) + } +} + +func TestOOOChunk_ResolveAfterWrap(t *testing.T) { + h, _ := newTestHead(t, 1000, compression.None, true) + require.NoError(t, h.Init(0)) + t.Cleanup(func() { require.NoError(t, h.Close()) }) + + s, _, _ := h.getOrCreate(1, labels.FromStrings("a", "b"), false) + s.ooo = &memSeriesOOOFields{firstOOOChunkID: chunks.HeadChunkID(oooChunkIDMask - 5)} + + ids := make([]chunks.HeadChunkID, 10) + rawIDs := make([]chunks.HeadChunkID, 10) + for i := range 10 { + ref := h.chunkDiskMapper.WriteChunk(s.ref, int64(i*100), int64(i*100+99), chunkenc.NewXORChunk(), true, handleChunkWriteError) + s.ooo.oooMmappedChunks = append(s.ooo.oooMmappedChunks, &mmappedChunk{ + ref: ref, minTime: int64(i * 100), maxTime: int64(i*100 + 99), + }) + ids[i] = s.oooHeadChunkID(i) + _, rawIDs[i], _ = unpackHeadChunkRef(chunks.ChunkRef(chunks.NewHeadChunkRef(s.ref, ids[i]))) + } + + // Simulate truncation of the first 8 chunks. + s.ooo.oooMmappedChunks = s.ooo.oooMmappedChunks[8:] + s.ooo.firstOOOChunkID = (s.ooo.firstOOOChunkID + 8) & (oooChunkIDMask - 1) + require.Equal(t, chunks.HeadChunkID(3), s.ooo.firstOOOChunkID) + + // Surviving chunks (original positions 8, 9) must resolve. + for _, pos := range []int{8, 9} { + chk, _, err := s.oooChunk(rawIDs[pos], h.chunkDiskMapper, nil) + require.NoError(t, err, "pos %d should resolve after truncation", pos) + require.NotNil(t, chk, "pos %d chunk must not be nil", pos) + } + + // Truncated chunks (original positions 0-7) must return ErrNotFound. + for pos := range 8 { + _, _, err := s.oooChunk(rawIDs[pos], h.chunkDiskMapper, nil) + require.Equal(t, storage.ErrNotFound, err, "pos %d should return ErrNotFound after truncation", pos) + } +} + +func TestOOOMmapGuardPreventsAliasing(t *testing.T) { + // The guard in mmapCurrentOOOHeadChunk caps oooMmappedChunks at + // oooChunkIDMask - 1 entries. With modular wrapping, this ensures + // unique chunk IDs within a single getOOOSeriesChunks call. + require.Equal(t, (1<<23)-1, oooChunkIDMask-1, + "guard bound must equal oooChunkIDMask-1 to prevent intra-call aliasing") + + h, _ := newTestHead(t, 1000, compression.None, true) + require.NoError(t, h.Init(0)) + t.Cleanup(func() { require.NoError(t, h.Close()) }) + + s, _, _ := h.getOrCreate(1, labels.FromStrings("a", "b"), false) + s.ooo = &memSeriesOOOFields{} + + seen := make(map[chunks.HeadChunkID]int) + s.ooo.firstOOOChunkID = chunks.HeadChunkID(oooChunkIDMask - 100) + for pos := range 200 { + id := s.oooHeadChunkID(pos) + require.Less(t, id, chunks.HeadChunkID(1<<24), "chunk ID must fit in 24 bits") + if prev, ok := seen[id]; ok { + t.Fatalf("position %d produced same HeadChunkID as position %d", pos, prev) + } + seen[id] = pos + } +} diff --git a/util/memorylimiter/memory_limiter.go b/util/memorylimiter/memory_limiter.go new file mode 100644 index 00000000000..b4cd53c5da9 --- /dev/null +++ b/util/memorylimiter/memory_limiter.go @@ -0,0 +1,440 @@ +// Copyright The Prometheus Authors +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package memorylimiter + +import ( + "context" + "fmt" + "log/slog" + "math" + "runtime/metrics" + "sync" + "time" + + "github.com/prometheus/client_golang/prometheus" + "go.uber.org/atomic" + + "github.com/prometheus/prometheus/config" +) + +// LimiterState represents the current memory pressure level. +type LimiterState int32 + +const ( + // StateOK indicates memory usage is below configured thresholds. + StateOK LimiterState = iota + // StateSoftLimit indicates memory usage has exceeded the soft limit threshold. + StateSoftLimit + // StateHardLimit indicates memory usage has exceeded the hard limit threshold. + StateHardLimit +) + +// String returns the string representation of LimiterState. +func (s LimiterState) String() string { + switch s { + case StateOK: + return "ok" + case StateSoftLimit: + return "soft" + case StateHardLimit: + return "hard" + default: + return "unknown" + } +} + +// MemoryLimiter provides memory pressure monitoring and enforcement controls. +type MemoryLimiter interface { + // State returns the current memory limiter state. + State() LimiterState + // AllowScrape returns true if target scraping is allowed. + AllowScrape() bool + // AllowOTLP returns true if OTLP write requests are allowed. + AllowOTLP() bool + // AllowRemoteWrite returns true if remote write requests are allowed. + AllowRemoteWrite() bool + // AllowRemoteRead returns true if remote read requests are allowed. + AllowRemoteRead() bool + // AllowFederation returns true if federation requests are allowed. + AllowFederation() bool + // AllowRecordingRules returns true if recording rules evaluation is allowed. + AllowRecordingRules() bool + // ApplyConfig updates the memory limiter configuration. + ApplyConfig(cfg *config.MemoryLimiterConfig) error + // Start starts periodic memory monitoring. + Start(ctx context.Context) + // Stop stops memory monitoring. + Stop() +} + +// memoryStats holds runtime memory statistics used by MemoryLimiter. +type memoryStats struct { + TotalBytes uint64 + FreeBytes uint64 + ReleasedBytes uint64 + GOMEMLIMIT uint64 + GCLimiterCycle uint64 +} + +// metricsReader is a function that retrieves current runtime memory statistics. +type metricsReader func() memoryStats + +func defaultMetricsReader() memoryStats { + samples := []metrics.Sample{ + {Name: "/memory/classes/total:bytes"}, + {Name: "/memory/classes/heap/free:bytes"}, + {Name: "/memory/classes/heap/released:bytes"}, + {Name: "/gc/gomemlimit:bytes"}, + {Name: "/gc/limiter/last-enabled:gc-cycle"}, + } + metrics.Read(samples) + var stats memoryStats + for _, s := range samples { + if s.Value.Kind() != metrics.KindUint64 { + continue + } + switch s.Name { + case "/memory/classes/total:bytes": + stats.TotalBytes = s.Value.Uint64() + case "/memory/classes/heap/free:bytes": + stats.FreeBytes = s.Value.Uint64() + case "/memory/classes/heap/released:bytes": + stats.ReleasedBytes = s.Value.Uint64() + case "/gc/gomemlimit:bytes": + stats.GOMEMLIMIT = s.Value.Uint64() + case "/gc/limiter/last-enabled:gc-cycle": + stats.GCLimiterCycle = s.Value.Uint64() + } + } + return stats +} + +// Manager implements MemoryLimiter by tracking runtime memory usage and enforcing limits. +type Manager struct { + logger *slog.Logger + + mu sync.RWMutex + config *config.MemoryLimiterConfig + + state atomic.Int32 + lastInUse atomic.Uint64 + lastGCLimiterCycle uint64 + gcLimiterInitialized bool + lastCheckTime time.Time + + metricsReader metricsReader + now func() time.Time + + metrics *memoryLimiterMetrics + + reloadCh chan struct{} + cancel context.CancelFunc + wg sync.WaitGroup +} + +// NewManager initializes and returns a new Manager. +func NewManager(cfg *config.MemoryLimiterConfig, logger *slog.Logger, reg prometheus.Registerer) (*Manager, error) { + if cfg != nil { + if err := cfg.Validate(); err != nil { + return nil, fmt.Errorf("invalid memory limiter config: %w", err) + } + } + + if logger == nil { + logger = slog.Default() + } + + m := &Manager{ + logger: logger.With("component", "memory limiter"), + config: cfg, + metricsReader: defaultMetricsReader, + now: time.Now, + metrics: newMemoryLimiterMetrics(reg), + reloadCh: make(chan struct{}, 1), + } + + return m, nil +} + +// ApplyConfig updates the Manager configuration. +func (m *Manager) ApplyConfig(cfg *config.MemoryLimiterConfig) error { + m.mu.Lock() + defer m.mu.Unlock() + + if cfg != nil { + if err := cfg.Validate(); err != nil { + return fmt.Errorf("invalid memory limiter config: %w", err) + } + } + + m.config = cfg + + select { + case m.reloadCh <- struct{}{}: + default: + } + + return nil +} + +// State returns the current LimiterState. +func (m *Manager) State() LimiterState { + if m == nil { + return StateOK + } + return LimiterState(m.state.Load()) +} + +// Start starts periodic memory monitoring in the background. +func (m *Manager) Start(ctx context.Context) { + m.mu.Lock() + if m.cancel != nil { + m.mu.Unlock() + return + } + loopCtx, cancel := context.WithCancel(ctx) + m.cancel = cancel + m.lastCheckTime = m.now() + m.wg.Add(1) + m.mu.Unlock() + + go m.run(loopCtx) +} + +// Stop stops the background memory monitoring loop. +func (m *Manager) Stop() { + m.mu.Lock() + if m.cancel != nil { + m.cancel() + m.cancel = nil + } + m.mu.Unlock() + m.wg.Wait() +} + +func (m *Manager) run(ctx context.Context) { + defer m.wg.Done() + + interval := 100 * time.Millisecond + m.mu.RLock() + if m.config != nil && m.config.CheckInterval > 0 { + interval = time.Duration(m.config.CheckInterval) + } + m.mu.RUnlock() + + ticker := time.NewTicker(interval) + defer ticker.Stop() + + // Initial evaluation. + m.Evaluate() + + for { + select { + case <-ctx.Done(): + return + case <-m.reloadCh: + m.mu.RLock() + newInterval := 100 * time.Millisecond + if m.config != nil && m.config.CheckInterval > 0 { + newInterval = time.Duration(m.config.CheckInterval) + } + m.mu.RUnlock() + ticker.Reset(newInterval) + m.Evaluate() + case <-ticker.C: + m.Evaluate() + } + } +} + +// Evaluate reads the runtime metrics and updates the limiter state. +func (m *Manager) Evaluate() { + m.mu.Lock() + defer m.mu.Unlock() + + stats := m.metricsReader() + totalBytes := stats.TotalBytes + freeBytes := stats.FreeBytes + releasedBytes := stats.ReleasedBytes + gomemlimit := stats.GOMEMLIMIT + gcLimiterCycle := stats.GCLimiterCycle + + if m.config == nil || gomemlimit == 0 || gomemlimit == math.MaxInt64 { + m.lastCheckTime = m.now() + oldState := LimiterState(m.state.Swap(int32(StateOK))) + if oldState != StateOK { + m.metrics.transitionsTotal.WithLabelValues(oldState.String(), StateOK.String()).Inc() + } + m.metrics.active.WithLabelValues("hard").Set(0) + m.metrics.active.WithLabelValues("soft").Set(0) + m.metrics.limitBytes.WithLabelValues("soft").Set(0) + m.metrics.limitBytes.WithLabelValues("hard").Set(0) + m.metrics.inUseBytes.Set(0) + return + } + + var inUse uint64 + if totalBytes > (freeBytes + releasedBytes) { + inUse = totalBytes - (freeBytes + releasedBytes) + } + m.lastInUse.Store(inUse) + + now := m.now() + elapsed := 0.0 + if !m.lastCheckTime.IsZero() { + elapsed = now.Sub(m.lastCheckTime).Seconds() + } + m.lastCheckTime = now + + oldState := LimiterState(m.state.Load()) + if elapsed > 0 { + switch oldState { + case StateSoftLimit: + m.metrics.engagedSecondsTotal.WithLabelValues("soft").Add(elapsed) + case StateHardLimit: + m.metrics.engagedSecondsTotal.WithLabelValues("soft").Add(elapsed) + m.metrics.engagedSecondsTotal.WithLabelValues("hard").Add(elapsed) + } + } + + pressureRatio := float64(inUse) / float64(gomemlimit) + + gcLimiterActive := m.gcLimiterInitialized && gcLimiterCycle > m.lastGCLimiterCycle + m.lastGCLimiterCycle = gcLimiterCycle + m.gcLimiterInitialized = true + + var newState LimiterState + switch { + case pressureRatio >= m.config.HardLimitRatio || gcLimiterActive: + newState = StateHardLimit + case pressureRatio >= m.config.SoftLimitRatio: + newState = StateSoftLimit + default: + newState = StateOK + } + + if newState != oldState { + m.state.Store(int32(newState)) + m.metrics.transitionsTotal.WithLabelValues(oldState.String(), newState.String()).Inc() + m.logger.Debug("Memory limiter state transition", + "from", oldState.String(), + "to", newState.String(), + "pressure_ratio", pressureRatio, + "in_use_bytes", inUse, + "gomemlimit", gomemlimit, + "gc_limiter_active", gcLimiterActive, + ) + } + + // Update gauges. + switch newState { + case StateHardLimit: + m.metrics.active.WithLabelValues("hard").Set(1) + m.metrics.active.WithLabelValues("soft").Set(1) + case StateSoftLimit: + m.metrics.active.WithLabelValues("hard").Set(0) + m.metrics.active.WithLabelValues("soft").Set(1) + default: + m.metrics.active.WithLabelValues("hard").Set(0) + m.metrics.active.WithLabelValues("soft").Set(0) + } + + m.metrics.limitBytes.WithLabelValues("soft").Set(float64(gomemlimit) * m.config.SoftLimitRatio) + m.metrics.limitBytes.WithLabelValues("hard").Set(float64(gomemlimit) * m.config.HardLimitRatio) + m.metrics.inUseBytes.Set(float64(inUse)) +} + +// AllowScrape returns true if scraping targets is allowed. +func (m *Manager) AllowScrape() bool { + if m == nil { + return true + } + m.mu.RLock() + cfg := m.config + m.mu.RUnlock() + if cfg == nil || !cfg.Enforcement.FailScrapes { + return true + } + return LimiterState(m.state.Load()) < StateHardLimit +} + +// AllowOTLP returns true if OTLP ingestion is allowed. +func (m *Manager) AllowOTLP() bool { + if m == nil { + return true + } + m.mu.RLock() + cfg := m.config + m.mu.RUnlock() + if cfg == nil || !cfg.Enforcement.RejectOTLP { + return true + } + return LimiterState(m.state.Load()) < StateHardLimit +} + +// AllowRemoteWrite returns true if remote write ingestion is allowed. +func (m *Manager) AllowRemoteWrite() bool { + if m == nil { + return true + } + m.mu.RLock() + cfg := m.config + m.mu.RUnlock() + if cfg == nil || !cfg.Enforcement.RejectRemoteWrite { + return true + } + return LimiterState(m.state.Load()) < StateHardLimit +} + +// AllowRemoteRead returns true if remote read queries are allowed. +func (m *Manager) AllowRemoteRead() bool { + if m == nil { + return true + } + m.mu.RLock() + cfg := m.config + m.mu.RUnlock() + if cfg == nil || !cfg.Enforcement.RejectRemoteRead { + return true + } + return LimiterState(m.state.Load()) < StateSoftLimit +} + +// AllowFederation returns true if federation endpoints are allowed. +func (m *Manager) AllowFederation() bool { + if m == nil { + return true + } + m.mu.RLock() + cfg := m.config + m.mu.RUnlock() + if cfg == nil || !cfg.Enforcement.RejectFederation { + return true + } + return LimiterState(m.state.Load()) < StateSoftLimit +} + +// AllowRecordingRules returns true if recording rule evaluation is allowed. +func (m *Manager) AllowRecordingRules() bool { + if m == nil { + return true + } + m.mu.RLock() + cfg := m.config + m.mu.RUnlock() + if cfg == nil || !cfg.Enforcement.PauseRecordingRules { + return true + } + return LimiterState(m.state.Load()) < StateHardLimit +} diff --git a/util/memorylimiter/memory_limiter_test.go b/util/memorylimiter/memory_limiter_test.go new file mode 100644 index 00000000000..21493490c0b --- /dev/null +++ b/util/memorylimiter/memory_limiter_test.go @@ -0,0 +1,148 @@ +// Copyright The Prometheus Authors +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package memorylimiter + +import ( + "log/slog" + "math" + "testing" + "time" + + "github.com/prometheus/client_golang/prometheus" + "github.com/prometheus/common/model" + "github.com/stretchr/testify/require" + + "github.com/prometheus/prometheus/config" +) + +func newMockMetricsReader(total, released, gomemlimit, gcLimiterCycle uint64) metricsReader { + return func() memoryStats { + return memoryStats{ + TotalBytes: total, + ReleasedBytes: released, + GOMEMLIMIT: gomemlimit, + GCLimiterCycle: gcLimiterCycle, + } + } +} + +func TestMemoryLimiterStateTransitions(t *testing.T) { + cfg := &config.MemoryLimiterConfig{ + CheckInterval: model.Duration(100 * time.Millisecond), + SoftLimitRatio: 0.70, + HardLimitRatio: 0.85, + Enforcement: config.MemoryLimiterEnforcement{ + RejectRemoteRead: true, + RejectFederation: true, + FailScrapes: true, + RejectOTLP: true, + RejectRemoteWrite: true, + PauseRecordingRules: true, + }, + } + + reg := prometheus.NewRegistry() + mgr, err := NewManager(cfg, slog.Default(), reg) + require.NoError(t, err) + + now := time.Now() + mgr.now = func() time.Time { return now } + + gomemlimit := uint64(1000 * 1024 * 1024) // 1000 MB + + // 1. Normal state: 500 MB in-use (50% ratio < 70%) + mgr.metricsReader = newMockMetricsReader(600*1024*1024, 100*1024*1024, gomemlimit, 0) + mgr.Evaluate() + require.Equal(t, StateOK, mgr.State()) + require.True(t, mgr.AllowScrape()) + require.True(t, mgr.AllowOTLP()) + require.True(t, mgr.AllowRemoteWrite()) + require.True(t, mgr.AllowRemoteRead()) + require.True(t, mgr.AllowFederation()) + require.True(t, mgr.AllowRecordingRules()) + + // 2. Soft limit state: 750 MB in-use (75% ratio >= 70%, < 85%) + now = now.Add(100 * time.Millisecond) + mgr.metricsReader = newMockMetricsReader(850*1024*1024, 100*1024*1024, gomemlimit, 0) + mgr.Evaluate() + require.Equal(t, StateSoftLimit, mgr.State()) + require.True(t, mgr.AllowScrape()) + require.True(t, mgr.AllowOTLP()) + require.True(t, mgr.AllowRemoteWrite()) + require.False(t, mgr.AllowRemoteRead()) + require.False(t, mgr.AllowFederation()) + require.True(t, mgr.AllowRecordingRules()) + + // 3. Hard limit state: 900 MB in-use (90% ratio >= 85%) + now = now.Add(100 * time.Millisecond) + mgr.metricsReader = newMockMetricsReader(1000*1024*1024, 100*1024*1024, gomemlimit, 0) + mgr.Evaluate() + require.Equal(t, StateHardLimit, mgr.State()) + require.False(t, mgr.AllowScrape()) + require.False(t, mgr.AllowOTLP()) + require.False(t, mgr.AllowRemoteWrite()) + require.False(t, mgr.AllowRemoteRead()) + require.False(t, mgr.AllowFederation()) + require.False(t, mgr.AllowRecordingRules()) + + // 4. Memory drops back to 400 MB (40% < 70%) -> Clean recovery to StateOK + now = now.Add(100 * time.Millisecond) + mgr.metricsReader = newMockMetricsReader(500*1024*1024, 100*1024*1024, gomemlimit, 0) + mgr.Evaluate() + require.Equal(t, StateOK, mgr.State()) + require.True(t, mgr.AllowScrape()) +} + +func TestGCLimiterEscalation(t *testing.T) { + cfg := &config.MemoryLimiterConfig{ + CheckInterval: model.Duration(100 * time.Millisecond), + SoftLimitRatio: 0.70, + HardLimitRatio: 0.85, + Enforcement: config.MemoryLimiterEnforcement{ + FailScrapes: true, + }, + } + + mgr, err := NewManager(cfg, slog.Default(), nil) + require.NoError(t, err) + + gomemlimit := uint64(1000 * 1024 * 1024) + + // In-use is low (500 MB / 50%), but GC CPU limiter engaged (cycle goes from 10 to 11) + mgr.metricsReader = newMockMetricsReader(500*1024*1024, 0, gomemlimit, 10) + mgr.Evaluate() + require.Equal(t, StateOK, mgr.State()) + + mgr.metricsReader = newMockMetricsReader(500*1024*1024, 0, gomemlimit, 11) + mgr.Evaluate() + require.Equal(t, StateHardLimit, mgr.State()) + require.False(t, mgr.AllowScrape()) +} + +func TestUnlimitedGOMEMLIMIT(t *testing.T) { + cfg := &config.MemoryLimiterConfig{ + CheckInterval: model.Duration(100 * time.Millisecond), + SoftLimitRatio: 0.70, + HardLimitRatio: 0.85, + } + + mgr, err := NewManager(cfg, slog.Default(), nil) + require.NoError(t, err) + + // GOMEMLIMIT is MaxInt64 (unlimited) + mgr.metricsReader = newMockMetricsReader(500*1024*1024, 0, math.MaxInt64, 0) + mgr.Evaluate() + require.Equal(t, StateOK, mgr.State()) + require.True(t, mgr.AllowScrape()) +} diff --git a/util/memorylimiter/metrics.go b/util/memorylimiter/metrics.go new file mode 100644 index 00000000000..5d2e4b0c7e4 --- /dev/null +++ b/util/memorylimiter/metrics.go @@ -0,0 +1,81 @@ +// Copyright The Prometheus Authors +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package memorylimiter + +import ( + "github.com/prometheus/client_golang/prometheus" +) + +type memoryLimiterMetrics struct { + active *prometheus.GaugeVec + engagedSecondsTotal *prometheus.CounterVec + transitionsTotal *prometheus.CounterVec + limitBytes *prometheus.GaugeVec + inUseBytes prometheus.Gauge +} + +func newMemoryLimiterMetrics(reg prometheus.Registerer) *memoryLimiterMetrics { + m := &memoryLimiterMetrics{ + active: prometheus.NewGaugeVec( + prometheus.GaugeOpts{ + Name: "prometheus_memory_limiter_active", + Help: "Boolean gauge indicating if a memory limiter threshold is currently engaged (1 for active, 0 for inactive).", + }, + []string{"limit"}, + ), + engagedSecondsTotal: prometheus.NewCounterVec( + prometheus.CounterOpts{ + Name: "prometheus_memory_limiter_engaged_seconds_total", + Help: "Total time in seconds spent with memory limiter thresholds engaged.", + }, + []string{"limit"}, + ), + transitionsTotal: prometheus.NewCounterVec( + prometheus.CounterOpts{ + Name: "prometheus_memory_limiter_transitions_total", + Help: "Total number of state transitions between memory limiter states.", + }, + []string{"from", "to"}, + ), + limitBytes: prometheus.NewGaugeVec( + prometheus.GaugeOpts{ + Name: "prometheus_memory_limiter_limit_bytes", + Help: "Evaluated memory limit in bytes for each threshold.", + }, + []string{"limit"}, + ), + inUseBytes: prometheus.NewGauge( + prometheus.GaugeOpts{ + Name: "prometheus_memory_limiter_in_use_bytes", + Help: "Current in-use memory in bytes evaluated by the memory limiter.", + }, + ), + } + + if reg != nil { + reg.MustRegister( + m.active, + m.engagedSecondsTotal, + m.transitionsTotal, + m.limitBytes, + m.inUseBytes, + ) + } + + // Initialize gauges with default 0 values. + m.active.WithLabelValues("soft").Set(0) + m.active.WithLabelValues("hard").Set(0) + + return m +} diff --git a/web/api/v1/api.go b/web/api/v1/api.go index 1aca4aaa749..246b1f5bc3c 100644 --- a/web/api/v1/api.go +++ b/web/api/v1/api.go @@ -59,6 +59,7 @@ import ( "github.com/prometheus/prometheus/util/annotations" "github.com/prometheus/prometheus/util/features" "github.com/prometheus/prometheus/util/httputil" + "github.com/prometheus/prometheus/util/memorylimiter" "github.com/prometheus/prometheus/util/notifications" "github.com/prometheus/prometheus/util/stats" ) @@ -271,6 +272,13 @@ type API struct { openAPIBuilder *OpenAPIBuilder parser parser.Parser + + memoryLimiter memorylimiter.MemoryLimiter +} + +// SetMemoryLimiter sets the memory limiter for API endpoints. +func (api *API) SetMemoryLimiter(ml memorylimiter.MemoryLimiter) { + api.memoryLimiter = ml } // NewAPI returns an initialized API type. @@ -2088,6 +2096,11 @@ func (api *API) notificationsSSE(w http.ResponseWriter, r *http.Request) { } func (api *API) remoteRead(w http.ResponseWriter, r *http.Request) { + if api.memoryLimiter != nil && !api.memoryLimiter.AllowRemoteRead() { + w.Header().Set("Retry-After", "5") + http.Error(w, "Service Unavailable: Memory limit exceeded", http.StatusServiceUnavailable) + return + } // This is only really for tests - this will never be nil IRL. if api.remoteReadHandler != nil { api.remoteReadHandler.ServeHTTP(w, r) @@ -2097,6 +2110,11 @@ func (api *API) remoteRead(w http.ResponseWriter, r *http.Request) { } func (api *API) remoteWrite(w http.ResponseWriter, r *http.Request) { + if api.memoryLimiter != nil && !api.memoryLimiter.AllowRemoteWrite() { + w.Header().Set("Retry-After", "5") + http.Error(w, "Service Unavailable: Memory limit exceeded", http.StatusServiceUnavailable) + return + } if api.remoteWriteHandler != nil { api.remoteWriteHandler.ServeHTTP(w, r) } else { @@ -2105,6 +2123,11 @@ func (api *API) remoteWrite(w http.ResponseWriter, r *http.Request) { } func (api *API) otlpWrite(w http.ResponseWriter, r *http.Request) { + if api.memoryLimiter != nil && !api.memoryLimiter.AllowOTLP() { + w.Header().Set("Retry-After", "5") + http.Error(w, "Service Unavailable: Memory limit exceeded", http.StatusServiceUnavailable) + return + } if api.otlpWriteHandler != nil { api.otlpWriteHandler.ServeHTTP(w, r) } else { diff --git a/web/api/v1/openapi_examples.go b/web/api/v1/openapi_examples.go index 71a7faff0ac..e0296eca73d 100644 --- a/web/api/v1/openapi_examples.go +++ b/web/api/v1/openapi_examples.go @@ -19,6 +19,7 @@ import ( "github.com/pb33f/libopenapi/datamodel/high/base" "github.com/pb33f/libopenapi/orderedmap" + "github.com/prometheus/prometheus/model/histogram" "github.com/prometheus/prometheus/model/labels" "github.com/prometheus/prometheus/promql" ) @@ -288,7 +289,26 @@ func queryResponseExamples() *orderedmap.Map[string, *base.Example] { Value: matrixExample(matrixResult), }) - // TODO: Add native histogram example. + histogramResult := promql.Vector{ + promql.Sample{ + Metric: labels.FromStrings("__name__", "http_request_duration_seconds", "job", "prometheus", "instance", "demo.prometheus.io:9090"), + T: 1767436620000, + H: &histogram.FloatHistogram{ + Schema: 1, + ZeroThreshold: 1e-128, + ZeroCount: 0, + Count: 12.5, + Sum: 42.1, + PositiveSpans: []histogram.Span{{Offset: 0, Length: 2}}, + PositiveBuckets: []float64{5, 7.5}, + }, + }, + } + + examples.Set("histogramResult", &base.Example{ + Summary: "Instant vector query with native histograms", + Value: vectorExample(histogramResult), + }) return examples } @@ -313,7 +333,29 @@ func queryRangeResponseExamples() *orderedmap.Map[string, *base.Example] { Value: matrixExample(matrixResult), }) - // TODO: Add native histogram example. + histogramResult := promql.Matrix{ + promql.Series{ + Metric: labels.FromStrings("__name__", "http_request_duration_seconds", "job", "prometheus", "instance", "demo.prometheus.io:9090"), + Histograms: []promql.HPoint{ + { + T: 1767433020000, + H: &histogram.FloatHistogram{ + Schema: 1, + ZeroThreshold: 1e-128, + Count: 12.5, + Sum: 42.1, + PositiveSpans: []histogram.Span{{Offset: 0, Length: 2}}, + PositiveBuckets: []float64{5, 7.5}, + }, + }, + }, + }, + } + + examples.Set("histogramResult", &base.Example{ + Summary: "Range query with native histograms", + Value: matrixExample(histogramResult), + }) return examples } diff --git a/web/api/v1/testdata/openapi_3.1_golden.yaml b/web/api/v1/testdata/openapi_3.1_golden.yaml index 71b1379f54c..8b666c4f7ea 100644 --- a/web/api/v1/testdata/openapi_3.1_golden.yaml +++ b/web/api/v1/testdata/openapi_3.1_golden.yaml @@ -127,6 +127,9 @@ paths: matrixResult: summary: 'Range vector query: up[5m]' value: {"status": "success", "data": {"resultType": "matrix", "result": [{"metric": {"__name__": "up", "instance": "demo.prometheus.io:9090", "job": "prometheus"}, "values": [[1767436320, "1"], [1767436620, "1"]]}]}} + histogramResult: + summary: Instant vector query with native histograms + value: {"status": "success", "data": {"resultType": "vector", "result": [{"metric": {"__name__": "http_request_duration_seconds", "instance": "demo.prometheus.io:9090", "job": "prometheus"}, "histogram": [1767436620, {"count": "12.5", "sum": "42.1", "buckets": [[0, "0.7071067811865475", "1", "5"], [0, "1", "1.414213562373095", "7.5"]]}]}]}} default: description: Error executing query. content: @@ -191,6 +194,9 @@ paths: matrixResult: summary: 'Range vector query: up[5m]' value: {"status": "success", "data": {"resultType": "matrix", "result": [{"metric": {"__name__": "up", "instance": "demo.prometheus.io:9090", "job": "prometheus"}, "values": [[1767436320, "1"], [1767436620, "1"]]}]}} + histogramResult: + summary: Instant vector query with native histograms + value: {"status": "success", "data": {"resultType": "vector", "result": [{"metric": {"__name__": "http_request_duration_seconds", "instance": "demo.prometheus.io:9090", "job": "prometheus"}, "histogram": [1767436620, {"count": "12.5", "sum": "42.1", "buckets": [[0, "0.7071067811865475", "1", "5"], [0, "1", "1.414213562373095", "7.5"]]}]}]}} default: description: Error executing instant query. content: @@ -348,6 +354,9 @@ paths: matrixResult: summary: 'Range query: rate(prometheus_http_requests_total[5m])' value: {"status": "success", "data": {"resultType": "matrix", "result": [{"metric": {"__name__": "up", "instance": "demo.prometheus.io:9090", "job": "prometheus"}, "values": [[1767433020, "1"], [1767434820, "1"], [1767436620, "1"]]}]}} + histogramResult: + summary: Range query with native histograms + value: {"status": "success", "data": {"resultType": "matrix", "result": [{"metric": {"__name__": "http_request_duration_seconds", "instance": "demo.prometheus.io:9090", "job": "prometheus"}, "histograms": [[1767433020, {"count": "12.5", "sum": "42.1", "buckets": [[0, "0.7071067811865475", "1", "5"], [0, "1", "1.414213562373095", "7.5"]]}]]}]}} default: description: Error executing range query. content: @@ -400,6 +409,9 @@ paths: matrixResult: summary: 'Range query: rate(prometheus_http_requests_total[5m])' value: {"status": "success", "data": {"resultType": "matrix", "result": [{"metric": {"__name__": "up", "instance": "demo.prometheus.io:9090", "job": "prometheus"}, "values": [[1767433020, "1"], [1767434820, "1"], [1767436620, "1"]]}]}} + histogramResult: + summary: Range query with native histograms + value: {"status": "success", "data": {"resultType": "matrix", "result": [{"metric": {"__name__": "http_request_duration_seconds", "instance": "demo.prometheus.io:9090", "job": "prometheus"}, "histograms": [[1767433020, {"count": "12.5", "sum": "42.1", "buckets": [[0, "0.7071067811865475", "1", "5"], [0, "1", "1.414213562373095", "7.5"]]}]]}]}} default: description: Error executing range query. content: diff --git a/web/api/v1/testdata/openapi_3.2_golden.yaml b/web/api/v1/testdata/openapi_3.2_golden.yaml index 7df14ae3fb7..32bfa40c55e 100644 --- a/web/api/v1/testdata/openapi_3.2_golden.yaml +++ b/web/api/v1/testdata/openapi_3.2_golden.yaml @@ -127,6 +127,9 @@ paths: matrixResult: summary: 'Range vector query: up[5m]' value: {"status": "success", "data": {"resultType": "matrix", "result": [{"metric": {"__name__": "up", "instance": "demo.prometheus.io:9090", "job": "prometheus"}, "values": [[1767436320, "1"], [1767436620, "1"]]}]}} + histogramResult: + summary: Instant vector query with native histograms + value: {"status": "success", "data": {"resultType": "vector", "result": [{"metric": {"__name__": "http_request_duration_seconds", "instance": "demo.prometheus.io:9090", "job": "prometheus"}, "histogram": [1767436620, {"count": "12.5", "sum": "42.1", "buckets": [[0, "0.7071067811865475", "1", "5"], [0, "1", "1.414213562373095", "7.5"]]}]}]}} default: description: Error executing query. content: @@ -191,6 +194,9 @@ paths: matrixResult: summary: 'Range vector query: up[5m]' value: {"status": "success", "data": {"resultType": "matrix", "result": [{"metric": {"__name__": "up", "instance": "demo.prometheus.io:9090", "job": "prometheus"}, "values": [[1767436320, "1"], [1767436620, "1"]]}]}} + histogramResult: + summary: Instant vector query with native histograms + value: {"status": "success", "data": {"resultType": "vector", "result": [{"metric": {"__name__": "http_request_duration_seconds", "instance": "demo.prometheus.io:9090", "job": "prometheus"}, "histogram": [1767436620, {"count": "12.5", "sum": "42.1", "buckets": [[0, "0.7071067811865475", "1", "5"], [0, "1", "1.414213562373095", "7.5"]]}]}]}} default: description: Error executing instant query. content: @@ -348,6 +354,9 @@ paths: matrixResult: summary: 'Range query: rate(prometheus_http_requests_total[5m])' value: {"status": "success", "data": {"resultType": "matrix", "result": [{"metric": {"__name__": "up", "instance": "demo.prometheus.io:9090", "job": "prometheus"}, "values": [[1767433020, "1"], [1767434820, "1"], [1767436620, "1"]]}]}} + histogramResult: + summary: Range query with native histograms + value: {"status": "success", "data": {"resultType": "matrix", "result": [{"metric": {"__name__": "http_request_duration_seconds", "instance": "demo.prometheus.io:9090", "job": "prometheus"}, "histograms": [[1767433020, {"count": "12.5", "sum": "42.1", "buckets": [[0, "0.7071067811865475", "1", "5"], [0, "1", "1.414213562373095", "7.5"]]}]]}]}} default: description: Error executing range query. content: @@ -400,6 +409,9 @@ paths: matrixResult: summary: 'Range query: rate(prometheus_http_requests_total[5m])' value: {"status": "success", "data": {"resultType": "matrix", "result": [{"metric": {"__name__": "up", "instance": "demo.prometheus.io:9090", "job": "prometheus"}, "values": [[1767433020, "1"], [1767434820, "1"], [1767436620, "1"]]}]}} + histogramResult: + summary: Range query with native histograms + value: {"status": "success", "data": {"resultType": "matrix", "result": [{"metric": {"__name__": "http_request_duration_seconds", "instance": "demo.prometheus.io:9090", "job": "prometheus"}, "histograms": [[1767433020, {"count": "12.5", "sum": "42.1", "buckets": [[0, "0.7071067811865475", "1", "5"], [0, "1", "1.414213562373095", "7.5"]]}]]}]}} default: description: Error executing range query. content: diff --git a/web/federate.go b/web/federate.go index 730c0cf8e2d..f554219adb4 100644 --- a/web/federate.go +++ b/web/federate.go @@ -53,6 +53,12 @@ func registerFederationMetrics(r prometheus.Registerer) { } func (h *Handler) federation(w http.ResponseWriter, req *http.Request) { + if h.options.MemoryLimiter != nil && !h.options.MemoryLimiter.AllowFederation() { + w.Header().Set("Retry-After", "5") + http.Error(w, "Service Unavailable: Memory limit exceeded", http.StatusServiceUnavailable) + return + } + h.mtx.RLock() defer h.mtx.RUnlock() diff --git a/web/ui/mantine-ui/package.json b/web/ui/mantine-ui/package.json index 5970094b6d0..9cf061441bc 100644 --- a/web/ui/mantine-ui/package.json +++ b/web/ui/mantine-ui/package.json @@ -54,7 +54,7 @@ "use-query-params": "^2.2.2" }, "devDependencies": { - "@eslint/compat": "^1.4.1", + "@eslint/compat": "^2.0.0", "@eslint/eslintrc": "^3.3.6", "@eslint/js": "^9.39.5", "@types/react": "^19.2.17", diff --git a/web/ui/mantine-ui/src/pages/query/DataTable.module.css b/web/ui/mantine-ui/src/pages/query/DataTable.module.css index 255173d9bd4..d1ea15f73a6 100644 --- a/web/ui/mantine-ui/src/pages/query/DataTable.module.css +++ b/web/ui/mantine-ui/src/pages/query/DataTable.module.css @@ -8,3 +8,17 @@ text-align: right; font-variant-numeric: tabular-nums; } + +/* The count is backed by a bar proportional to the largest bucket count, so + that the table shows the shape of the distribution as well as exact values. */ +.bucketCountCell { + text-align: right; + min-width: 5rem; + background-image: linear-gradient( + to right, + light-dark(rgba(45, 180, 83, 0.25), rgba(45, 180, 83, 0.35)) 0 + var(--bucket-count-fraction), + transparent var(--bucket-count-fraction) 100% + ); + background-repeat: no-repeat; +} diff --git a/web/ui/mantine-ui/src/pages/query/DataTable.tsx b/web/ui/mantine-ui/src/pages/query/DataTable.tsx index 375b033edab..39a14287591 100644 --- a/web/ui/mantine-ui/src/pages/query/DataTable.tsx +++ b/web/ui/mantine-ui/src/pages/query/DataTable.tsx @@ -4,7 +4,6 @@ import { Alert, Box, SegmentedControl, - ScrollArea, Group, Stack, Text, @@ -175,37 +174,55 @@ const DataTable: FC = ({ ); }; -const histogramTable = (h: Histogram): ReactNode => ( - - - { + const buckets = h.buckets || []; + // The bucket with the highest count sets the scale for the in-cell count bars. + const maxCount = buckets.reduce( + (max, b) => Math.max(max, parseFloat(b[3])), + 0 + ); + + return ( + // A native scroll container (rather than Mantine's ScrollArea) is used so + // that the sticky header positions itself against the scrolling element. + +
- Bucket range - Count - - - {h.buckets?.map((b, i) => ( - - - {bucketRangeString(b)} - - {b[3]} + + + Bucket range + Count - ))} - - -
-); + + + {buckets.map((b, i) => ( + + {bucketRangeString(b)} + 0 + ? `${(parseFloat(b[3]) / maxCount) * 100}%` + : "0%", + } + } + > + {b[3]} + + + ))} + + + + ); +}; export default DataTable; diff --git a/web/ui/mantine-ui/src/promql/tools/go.mod b/web/ui/mantine-ui/src/promql/tools/go.mod index 367faf2ec03..c3cc042ab94 100644 --- a/web/ui/mantine-ui/src/promql/tools/go.mod +++ b/web/ui/mantine-ui/src/promql/tools/go.mod @@ -1,6 +1,6 @@ module github.com/prometheus/prometheus/web/ui/mantine-ui/src/promql/tools -go 1.25.8 +go 1.25.10 require ( github.com/grafana/regexp v0.0.0-20250905093917-f7b3be9d1853 diff --git a/web/ui/module/codemirror-promql/package.json b/web/ui/module/codemirror-promql/package.json index 7776b1fcaa5..c40efeab963 100644 --- a/web/ui/module/codemirror-promql/package.json +++ b/web/ui/module/codemirror-promql/package.json @@ -38,7 +38,7 @@ "@codemirror/lint": "^6.9.7", "@codemirror/state": "^6.7.1", "@codemirror/view": "^6.43.6", - "@eslint/compat": "^1.4.1", + "@eslint/compat": "^2.0.0", "@eslint/eslintrc": "^3.3.6", "@eslint/js": "^9.39.5", "@lezer/common": "^1.5.2", diff --git a/web/ui/pnpm-lock.yaml b/web/ui/pnpm-lock.yaml index 05d6109f3e7..b526b1b1b75 100644 --- a/web/ui/pnpm-lock.yaml +++ b/web/ui/pnpm-lock.yaml @@ -13,25 +13,25 @@ importers: version: 29.5.14 '@typescript-eslint/eslint-plugin': specifier: ^8.65.0 - version: 8.65.0(@typescript-eslint/parser@8.65.0(eslint@9.39.5)(typescript@5.9.3))(eslint@9.39.5)(typescript@5.9.3) + version: 8.66.0(@typescript-eslint/parser@8.66.0(eslint@9.39.5(supports-color@8.1.1))(supports-color@8.1.1)(typescript@5.9.3))(eslint@9.39.5(supports-color@8.1.1))(supports-color@8.1.1)(typescript@5.9.3) '@typescript-eslint/parser': specifier: ^8.65.0 - version: 8.65.0(eslint@9.39.5)(typescript@5.9.3) + version: 8.66.0(eslint@9.39.5(supports-color@8.1.1))(supports-color@8.1.1)(typescript@5.9.3) eslint-config-prettier: specifier: ^10.1.8 - version: 10.1.8(eslint@9.39.5) + version: 10.1.8(eslint@9.39.5(supports-color@8.1.1)) prettier: specifier: ^3.9.6 version: 3.9.6 ts-jest: specifier: ^29.4.12 - version: 29.4.12(@babel/core@7.29.7)(@jest/transform@30.4.1)(@jest/types@30.4.1)(babel-jest@30.4.1(@babel/core@7.29.7))(jest-util@30.4.1)(jest@30.4.2(@types/node@26.0.1))(typescript@5.9.3) + version: 29.4.12(@babel/core@7.29.7(supports-color@8.1.1))(@jest/transform@30.4.1(supports-color@8.1.1))(@jest/types@30.4.1)(babel-jest@30.4.1(@babel/core@7.29.7(supports-color@8.1.1))(supports-color@8.1.1))(esbuild@0.25.12)(jest-util@30.4.1)(jest@30.4.2(@types/node@26.0.1)(supports-color@8.1.1))(typescript@5.9.3) typescript: specifier: ^5.9.3 version: 5.9.3 vite: specifier: ^6.4.3 - version: 6.4.3(@types/node@26.0.1)(sugarss@5.0.1(postcss@8.5.23)) + version: 6.4.3(@types/node@26.0.1)(sugarss@5.0.1(postcss@8.5.26)) mantine-ui: dependencies: @@ -55,7 +55,7 @@ importers: version: 6.7.1 '@codemirror/view': specifier: ^6.43.6 - version: 6.43.6 + version: 6.43.8 '@floating-ui/dom': specifier: ^1.8.0 version: 1.8.0 @@ -67,19 +67,19 @@ importers: version: 1.2.3 '@mantine/code-highlight': specifier: ^9.5.0 - version: 9.5.0(@mantine/core@9.5.0(@mantine/hooks@9.5.0(react@19.2.8))(@types/react@19.2.17)(react-dom@19.2.8(react@19.2.8))(react@19.2.8))(@mantine/hooks@9.5.0(react@19.2.8))(react-dom@19.2.8(react@19.2.8))(react@19.2.8) + version: 9.5.1(@mantine/core@9.5.1(@mantine/hooks@9.5.1(react@19.2.8))(@types/react@19.2.18)(react-dom@19.2.8(react@19.2.8))(react@19.2.8))(@mantine/hooks@9.5.1(react@19.2.8))(react-dom@19.2.8(react@19.2.8))(react@19.2.8) '@mantine/core': specifier: ^9.5.0 - version: 9.5.0(@mantine/hooks@9.5.0(react@19.2.8))(@types/react@19.2.17)(react-dom@19.2.8(react@19.2.8))(react@19.2.8) + version: 9.5.1(@mantine/hooks@9.5.1(react@19.2.8))(@types/react@19.2.18)(react-dom@19.2.8(react@19.2.8))(react@19.2.8) '@mantine/dates': specifier: ^9.5.0 - version: 9.5.0(@mantine/core@9.5.0(@mantine/hooks@9.5.0(react@19.2.8))(@types/react@19.2.17)(react-dom@19.2.8(react@19.2.8))(react@19.2.8))(@mantine/hooks@9.5.0(react@19.2.8))(dayjs@1.11.21)(react-dom@19.2.8(react@19.2.8))(react@19.2.8) + version: 9.5.1(@mantine/core@9.5.1(@mantine/hooks@9.5.1(react@19.2.8))(@types/react@19.2.18)(react-dom@19.2.8(react@19.2.8))(react@19.2.8))(@mantine/hooks@9.5.1(react@19.2.8))(dayjs@1.11.21)(react-dom@19.2.8(react@19.2.8))(react@19.2.8) '@mantine/hooks': specifier: ^9.5.0 - version: 9.5.0(react@19.2.8) + version: 9.5.1(react@19.2.8) '@mantine/notifications': specifier: ^9.5.0 - version: 9.5.0(@mantine/core@9.5.0(@mantine/hooks@9.5.0(react@19.2.8))(@types/react@19.2.17)(react-dom@19.2.8(react@19.2.8))(react@19.2.8))(@mantine/hooks@9.5.0(react@19.2.8))(react-dom@19.2.8(react@19.2.8))(react@19.2.8) + version: 9.5.1(@mantine/core@9.5.1(@mantine/hooks@9.5.1(react@19.2.8))(@types/react@19.2.18)(react-dom@19.2.8(react@19.2.8))(react@19.2.8))(@mantine/hooks@9.5.1(react@19.2.8))(react-dom@19.2.8(react@19.2.8))(react@19.2.8) '@microsoft/fetch-event-source': specifier: ^2.0.1 version: 2.0.1 @@ -94,10 +94,10 @@ importers: version: link:../module/codemirror-promql '@reduxjs/toolkit': specifier: ^2.12.0 - version: 2.12.0(react-redux@9.3.0(@types/react@19.2.17)(react@19.2.8)(redux@5.0.1))(react@19.2.8) + version: 2.12.0(react-redux@9.3.0(@types/react@19.2.18)(react@19.2.8)(redux@5.0.1))(react@19.2.8) '@tabler/icons-react': specifier: ^3.45.0 - version: 3.45.0(react@19.2.8) + version: 3.46.0(react@19.2.8) '@tanstack/react-query': specifier: ^5.101.4 version: 5.101.4(react@19.2.8) @@ -106,16 +106,16 @@ importers: version: 6.10.0(@testing-library/dom@10.4.1) '@testing-library/react': specifier: ^16.3.2 - version: 16.3.2(@testing-library/dom@10.4.1)(@types/react-dom@19.2.3(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.8(react@19.2.8))(react@19.2.8) + version: 16.3.2(@testing-library/dom@10.4.1)(@types/react-dom@19.2.4(@types/react@19.2.18))(@types/react@19.2.18)(react-dom@19.2.8(react@19.2.8))(react@19.2.8) '@types/lodash': specifier: ^4.17.24 - version: 4.17.24 + version: 4.17.25 '@types/sanitize-html': specifier: ^2.16.1 version: 2.16.1 '@uiw/react-codemirror': specifier: ^4.25.11 - version: 4.25.11(@babel/runtime@7.29.7)(@codemirror/autocomplete@6.20.3)(@codemirror/language@6.12.4)(@codemirror/lint@6.9.7)(@codemirror/search@6.7.1)(@codemirror/state@6.7.1)(@codemirror/theme-one-dark@6.1.3)(@codemirror/view@6.43.6)(codemirror@6.0.2)(react-dom@19.2.8(react@19.2.8))(react@19.2.8) + version: 4.25.11(@babel/runtime@7.29.7)(@codemirror/autocomplete@6.20.3)(@codemirror/language@6.12.4)(@codemirror/lint@6.9.7)(@codemirror/search@6.7.1)(@codemirror/state@6.7.1)(@codemirror/theme-one-dark@6.1.3)(@codemirror/view@6.43.8)(codemirror@6.0.2)(react-dom@19.2.8(react@19.2.8))(react@19.2.8) clsx: specifier: ^2.1.1 version: 2.1.1 @@ -139,10 +139,10 @@ importers: version: 6.1.1(react@19.2.8) react-redux: specifier: ^9.3.0 - version: 9.3.0(@types/react@19.2.17)(react@19.2.8)(redux@5.0.1) + version: 9.3.0(@types/react@19.2.18)(react@19.2.8)(redux@5.0.1) react-router-dom: specifier: ^7.18.1 - version: 7.18.1(react-dom@19.2.8(react@19.2.8))(react@19.2.8) + version: 7.18.2(react-dom@19.2.8(react@19.2.8))(react@19.2.8) sanitize-html: specifier: ^2.17.6 version: 2.17.6 @@ -154,65 +154,65 @@ importers: version: 1.2.4(react@19.2.8)(uplot@1.6.32) use-query-params: specifier: ^2.2.2 - version: 2.2.2(react-dom@19.2.8(react@19.2.8))(react-router-dom@7.18.1(react-dom@19.2.8(react@19.2.8))(react@19.2.8))(react@19.2.8) + version: 2.2.2(react-dom@19.2.8(react@19.2.8))(react-router-dom@7.18.2(react-dom@19.2.8(react@19.2.8))(react@19.2.8))(react@19.2.8) devDependencies: '@eslint/compat': - specifier: ^1.4.1 - version: 1.4.1(eslint@9.39.5) + specifier: ^2.0.0 + version: 2.1.0(eslint@9.39.5(supports-color@8.1.1)) '@eslint/eslintrc': specifier: ^3.3.6 - version: 3.3.6 + version: 3.3.6(supports-color@8.1.1) '@eslint/js': specifier: ^9.39.5 version: 9.39.5 '@types/react': specifier: ^19.2.17 - version: 19.2.17 + version: 19.2.18 '@types/react-dom': specifier: ^19.2.3 - version: 19.2.3(@types/react@19.2.17) + version: 19.2.4(@types/react@19.2.18) '@typescript-eslint/eslint-plugin': specifier: ^8.65.0 - version: 8.65.0(@typescript-eslint/parser@8.65.0(eslint@9.39.5)(typescript@5.9.3))(eslint@9.39.5)(typescript@5.9.3) + version: 8.66.0(@typescript-eslint/parser@8.66.0(eslint@9.39.5(supports-color@8.1.1))(supports-color@8.1.1)(typescript@5.9.3))(eslint@9.39.5(supports-color@8.1.1))(supports-color@8.1.1)(typescript@5.9.3) '@typescript-eslint/parser': specifier: ^8.65.0 - version: 8.65.0(eslint@9.39.5)(typescript@5.9.3) + version: 8.66.0(eslint@9.39.5(supports-color@8.1.1))(supports-color@8.1.1)(typescript@5.9.3) '@vitejs/plugin-react': specifier: ^4.7.0 - version: 4.7.0(vite@6.4.3(@types/node@26.0.1)(sugarss@5.0.1(postcss@8.5.23))) + version: 4.7.0(supports-color@8.1.1)(vite@6.4.3(@types/node@26.0.1)(sugarss@5.0.1(postcss@8.5.26))) eslint: specifier: ^9.39.5 - version: 9.39.5 + version: 9.39.5(supports-color@8.1.1) eslint-plugin-react-hooks: specifier: ^5.2.0 - version: 5.2.0(eslint@9.39.5) + version: 5.2.0(eslint@9.39.5(supports-color@8.1.1)) eslint-plugin-react-refresh: specifier: ^0.5.3 - version: 0.5.3(eslint@9.39.5) + version: 0.5.3(eslint@9.39.5(supports-color@8.1.1)) globals: specifier: ^16.5.0 version: 16.5.0 jsdom: specifier: ^25.0.1 - version: 25.0.1 + version: 25.0.1(supports-color@8.1.1) postcss: specifier: ^8.5.23 - version: 8.5.23 + version: 8.5.26 postcss-preset-mantine: specifier: ^1.18.0 - version: 1.18.0(postcss@8.5.23) + version: 1.18.0(postcss@8.5.26) postcss-simple-vars: specifier: ^7.0.1 - version: 7.0.1(postcss@8.5.23) + version: 7.0.1(postcss@8.5.26) rollup-plugin-license: specifier: ^3.7.1 - version: 3.7.1(picomatch@4.0.4)(rollup@4.62.3) + version: 3.7.1(picomatch@4.0.4)(rollup@4.62.4) vite: specifier: ^6.4.3 - version: 6.4.3(@types/node@26.0.1)(sugarss@5.0.1(postcss@8.5.23)) + version: 6.4.3(@types/node@26.0.1)(sugarss@5.0.1(postcss@8.5.26)) vitest: specifier: ^3.2.7 - version: 3.2.7(@types/node@26.0.1)(jsdom@25.0.1)(sugarss@5.0.1(postcss@8.5.23)) + version: 3.2.7(@types/node@26.0.1)(jsdom@25.0.1(supports-color@8.1.1))(sugarss@5.0.1(postcss@8.5.26))(supports-color@8.1.1) module/codemirror-promql: dependencies: @@ -237,13 +237,13 @@ importers: version: 6.7.1 '@codemirror/view': specifier: ^6.43.6 - version: 6.43.6 + version: 6.43.8 '@eslint/compat': - specifier: ^1.4.1 - version: 1.4.1(eslint@9.39.5) + specifier: ^2.0.0 + version: 2.1.0(eslint@9.39.5(supports-color@8.1.1)) '@eslint/eslintrc': specifier: ^3.3.6 - version: 3.3.6 + version: 3.3.6(supports-color@8.1.1) '@eslint/js': specifier: ^9.39.5 version: 9.39.5 @@ -258,25 +258,25 @@ importers: version: 1.4.10 '@typescript-eslint/eslint-plugin': specifier: ^8.65.0 - version: 8.65.0(@typescript-eslint/parser@8.65.0(eslint@9.39.5)(typescript@5.9.3))(eslint@9.39.5)(typescript@5.9.3) + version: 8.66.0(@typescript-eslint/parser@8.66.0(eslint@9.39.5(supports-color@8.1.1))(supports-color@8.1.1)(typescript@5.9.3))(eslint@9.39.5(supports-color@8.1.1))(supports-color@8.1.1)(typescript@5.9.3) '@typescript-eslint/parser': specifier: ^8.65.0 - version: 8.65.0(eslint@9.39.5)(typescript@5.9.3) + version: 8.66.0(eslint@9.39.5(supports-color@8.1.1))(supports-color@8.1.1)(typescript@5.9.3) eslint: specifier: ^9.39.5 - version: 9.39.5 + version: 9.39.5(supports-color@8.1.1) eslint-plugin-prettier: specifier: ^5.5.6 - version: 5.5.6(eslint-config-prettier@10.1.8(eslint@9.39.5))(eslint@9.39.5)(prettier@3.9.6) + version: 5.5.6(eslint-config-prettier@10.1.8(eslint@9.39.5(supports-color@8.1.1)))(eslint@9.39.5(supports-color@8.1.1))(prettier@3.9.6) isomorphic-fetch: specifier: ^3.0.0 version: 3.0.0 jest: specifier: ^30.4.2 - version: 30.4.2(@types/node@26.0.1) + version: 30.4.2(@types/node@26.0.1)(supports-color@8.1.1) nock: specifier: ^14.0.16 - version: 14.0.16 + version: 14.0.17 module/lezer-promql: devDependencies: @@ -291,13 +291,13 @@ importers: version: 1.4.10 '@rollup/plugin-node-resolve': specifier: ^16.0.3 - version: 16.0.3(rollup@4.62.3) + version: 16.0.3(rollup@4.62.4) jest: specifier: ^30.4.2 - version: 30.4.2(@types/node@26.0.1) + version: 30.4.2(@types/node@26.0.1)(supports-color@8.1.1) rollup: specifier: ^4.62.3 - version: 4.62.3 + version: 4.62.4 packages: @@ -509,8 +509,8 @@ packages: '@codemirror/theme-one-dark@6.1.3': resolution: {integrity: sha512-NzBdIvEJmx6fjeremiGp3t/okrLPYT0d9orIc7AFun8oZcRk58aejkqhv6spnz4MLAevrKNPMQYXEWMg4s+sKA==} - '@codemirror/view@6.43.6': - resolution: {integrity: sha512-EVunGSYN1wz1p75WY1s3Xg7t3i8Yol0kGZGizNdX9BUFgMFILYVe8/u6EVpo7Ff5PwbZuILb4QAq7IZoKzIEQA==} + '@codemirror/view@6.43.8': + resolution: {integrity: sha512-qtItTDssZ/5GFfi94hrILu9j/VUeFPDPkhovEfmWFj2ipTxnzPB8DdHgfbb8HYTzLTYhrndKmyQxXUz/PDLenw==} '@csstools/color-helpers@5.1.0': resolution: {integrity: sha512-S11EXWJyy0Mz5SYvRmY8nJYTFFd1LCNV+7cXyAgQtOOuzb4EsgfqDufL+9esx72/eLhsRdGZwaldu/h+E4t4BA==} @@ -705,8 +705,8 @@ packages: cpu: [x64] os: [win32] - '@eslint-community/eslint-utils@4.9.1': - resolution: {integrity: sha512-phrYmNiYppR7znFEdqgfWHXR6NCkZEK7hwWDHZUjit/2/U0r6XvkDl0SYnoM51Hq7FhCGdLDT6zxCCOY1hexsQ==} + '@eslint-community/eslint-utils@4.10.1': + resolution: {integrity: sha512-cuadcxVFE8sDK6iWJbs8Sn0av2Nrh2QSGQhVlBW9AaAHqHwjWsZHT8LJ4hFGPh7ASBV2deFdM7H/DPjulmh8rg==} engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} peerDependencies: eslint: ^6.0.0 || ^7.0.0 || >=8.0.0 @@ -715,11 +715,11 @@ packages: resolution: {integrity: sha512-EriSTlt5OC9/7SXkRSCAhfSxxoSUgBm33OH+IkwbdpgoqsSsUg7y3uh+IICI/Qg4BBWr3U2i39RpmycbxMq4ew==} engines: {node: ^12.0.0 || ^14.0.0 || >=16.0.0} - '@eslint/compat@1.4.1': - resolution: {integrity: sha512-cfO82V9zxxGBxcQDr1lfaYB7wykTa0b00mGa36FrJl7iTFd0Z2cHfEYuxcBRP/iNijCsWsEkA+jzT8hGYmv33w==} - engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + '@eslint/compat@2.1.0': + resolution: {integrity: sha512-LgaSCymEpw7tF53xvDw9SNsraPb1IBHxpdABIOM0hW8UAlP8znrjYtuxfR58FSJ3L9BhwD+FaPRFQpZq84Nh6g==} + engines: {node: ^20.19.0 || ^22.13.0 || >=24} peerDependencies: - eslint: ^8.40 || 9 + eslint: ^8.40 || 9 || 10 peerDependenciesMeta: eslint: optional: true @@ -736,6 +736,10 @@ packages: resolution: {integrity: sha512-yL/sLrpmtDaFEiUj1osRP4TI2MDz1AddJL+jZ7KSqvBuliN4xqYY54IfdN8qD8Toa6g1iloph1fxQNkjOxrrpQ==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + '@eslint/core@1.2.1': + resolution: {integrity: sha512-MwcE1P+AZ4C6DWlpin/OmOA54mmIZ/+xZuJiQd4SyB29oAJjN30UW9wkKNptW2ctp4cEsvhlLY/CsQ1uoHDloQ==} + engines: {node: ^20.19.0 || ^22.13.0 || >=24} + '@eslint/eslintrc@3.3.6': resolution: {integrity: sha512-l2Ul9PrHsPCKcEY/ac7VgFj9D80C7S68sOKc618SyHDPK36s1XcFebXY0iTzUVn4Yq+YbwvSnDmCz9yxjX+QrA==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} @@ -758,14 +762,14 @@ packages: '@floating-ui/dom@1.8.0': resolution: {integrity: sha512-yXSrzeHZBTZadLOlfyhCkJHNeLJnHRnRInwdZ40L7ZiaAtrBwoYlsDrX3v5zB1Utk7CLfzcOVnVVWoXEky7Ceg==} - '@floating-ui/react-dom@2.1.8': - resolution: {integrity: sha512-cC52bHwM/n/CxS87FH0yWdngEZrjdtLW/qVruo68qg+prK7ZQ4YGdut2GyDVpoGeAYe/h899rVeOVm6Oi40k2A==} + '@floating-ui/react-dom@2.1.9': + resolution: {integrity: sha512-JDjEFGCpImxDCA7JJKviA0M9+RtmJdj0m/NVU5IMgBK+AmZouAQQ7/+2GLH0GXXY0YMw9oXPB8hKdbPYg5QLYg==} peerDependencies: react: '>=16.8.0' react-dom: '>=16.8.0' - '@floating-ui/react@0.27.19': - resolution: {integrity: sha512-31B8h5mm8YxotlE7/AU/PhNAl8eWxAmjL/v2QOxroDNkTFLk3Uu82u63N3b6TXa4EGJeeZLVcd/9AlNlVqzeog==} + '@floating-ui/react@0.27.20': + resolution: {integrity: sha512-CMqMy7OaXl9W0eq1Uy7L7i2Y/anPvHmFmESd2CEw0t5YvZhcVCeo4MBevAmswRllX7Y2dEidA4ozGPunLSTQpw==} peerDependencies: react: '>=17.0.0' react-dom: '>=17.0.0' @@ -928,45 +932,45 @@ packages: '@lezer/lr@1.4.10': resolution: {integrity: sha512-rnCpTIBafOx4mRp43xOxDJbFipJm/c0cia/V5TiGlhmMa+wsSdoGmUN3w5Bqrks/09Q/D4tNAmWaT8p6NRi77A==} - '@mantine/code-highlight@9.5.0': - resolution: {integrity: sha512-Soidz7O/AtOGlbKgqfH0OgAei2l4TDFw1L3Ux1DZQ2CqJO4ILPHTjuXXNhtNmeH4iTjsUoTjlReTAUfAw+QIDA==} + '@mantine/code-highlight@9.5.1': + resolution: {integrity: sha512-Mt/vY6FSb7fv9GBgPxn+fCD+pnhuNL84B+9nbHZ9Oh6X4oSEyL5iCeBXKPusJv4c7tLow/WBySqB41dAc39kng==} peerDependencies: - '@mantine/core': 9.5.0 - '@mantine/hooks': 9.5.0 + '@mantine/core': 9.5.1 + '@mantine/hooks': 9.5.1 react: ^19.2.0 react-dom: ^19.2.0 - '@mantine/core@9.5.0': - resolution: {integrity: sha512-lUZtPfW+ZIXthofPyw+SVgWNiV/OkJ498r3OZeuekPgM23p2AspqHzHjEGhe5DMSTyhma6BhIHF2H10dAp0ibw==} + '@mantine/core@9.5.1': + resolution: {integrity: sha512-3olDOYJBfW4kR37Aqdy/+FnYG7iNb5SPzOGeCp9dDxnt65K94sEqETDnXGJptOMO2xLm4KLJ/eBt3IIhJA7Z4Q==} peerDependencies: - '@mantine/hooks': 9.5.0 + '@mantine/hooks': 9.5.1 react: ^19.2.0 react-dom: ^19.2.0 - '@mantine/dates@9.5.0': - resolution: {integrity: sha512-uHDHDkV7WPtMXCIayDCgHKxTrvmG37rhsx8UDyekRitO0dHZ7f9F7x+xrG2QVYl0c0t3xeJE9+/RjNHSnVcP7Q==} + '@mantine/dates@9.5.1': + resolution: {integrity: sha512-1FTIgF8L6AKEb+Ql53zVyCCp4JxvQp/AUDts5T/JEI7U0CZGpzg+FHGtmNShLR4ONuOfzOV1gkgU8INbxVJjag==} peerDependencies: - '@mantine/core': 9.5.0 - '@mantine/hooks': 9.5.0 + '@mantine/core': 9.5.1 + '@mantine/hooks': 9.5.1 dayjs: '>=1.0.0' react: ^19.2.0 react-dom: ^19.2.0 - '@mantine/hooks@9.5.0': - resolution: {integrity: sha512-d67+7dQW0ZJFiWXqZgwcPrZK0KxKMzAX+Sv663g40xhISseiUoK0f8k/Ss2amOA09IhFayeeaqprVRc4Fp5yEw==} + '@mantine/hooks@9.5.1': + resolution: {integrity: sha512-2sK9OdWvrzKBOuWxLfQA5qcAJzxpzqNlKumaP7Uq0i7LDBQeY/sYgNiBWLwtW+iZw6fFXwPf0nI7q5VVpvqnNQ==} peerDependencies: react: ^19.2.0 - '@mantine/notifications@9.5.0': - resolution: {integrity: sha512-IgLO0zUppRh17TbOI5kku5pyKCNoEOAwemJi/H+gmq20QQFIwd+SxJLQvGT+OrKib2eWDlG+Tz6DJSwx3rn+Vg==} + '@mantine/notifications@9.5.1': + resolution: {integrity: sha512-/MIGWag8U20HTM4gOGSNVhmQ0n6YM2gdSR1NbtBffSh77nuzwPjr68UmpMc2WHFMi8OBlrSIcw9Xpe3YPfgnvQ==} peerDependencies: - '@mantine/core': 9.5.0 - '@mantine/hooks': 9.5.0 + '@mantine/core': 9.5.1 + '@mantine/hooks': 9.5.1 react: ^19.2.0 react-dom: ^19.2.0 - '@mantine/store@9.5.0': - resolution: {integrity: sha512-MeJybawnPCCIcfrpSjtbRERJXZWAdOKSp3afsl82e5HZZtKJepgvktD5lcS9hRrrAdGWywi7gcMduLT0bUHDzw==} + '@mantine/store@9.5.1': + resolution: {integrity: sha512-nDmA9S+qnQQ61KYgph06Wt2cx1tj3Z6eeyK3HvFeuLb5FcGycbITsVy/+3LltH2qdqkpNeAA9wQ926NFjn5hvA==} peerDependencies: react: ^19.2.0 @@ -980,6 +984,13 @@ packages: resolution: {integrity: sha512-VVPPgHyQ6ShqnrmDWuxjmUIsO9gWyOZFmuOfLd9LfBGQJwZfy0gvv9pbHSJuoFNIYC7ZDX9aoFwowjcdSC4E8w==} engines: {node: '>=18'} + '@napi-rs/lzma-linux-x64-gnu@1.5.1': + resolution: {integrity: sha512-oTXEIha4SsuXdTA4Iyskj0kpdx2yVXdhd75c2v3xGrHFfVMsbhTPZU/nMPL4sWKo4pBHm3aucLaqGlF696dTyQ==} + engines: {node: ^22.20 || ^24.12 || >=25} + cpu: [x64] + os: [linux] + libc: [glibc] + '@napi-rs/wasm-runtime@1.1.6': resolution: {integrity: sha512-ZLv/JdUfkvOy9eCnnBaGfiO+XimbjebAeO+MRQqD/B+FR1tnRN0tpKSJHRbE8sFfS6aqsXZ67TQjfwfsxULVbg==} peerDependencies: @@ -1041,141 +1052,141 @@ packages: rollup: optional: true - '@rollup/rollup-android-arm-eabi@4.62.3': - resolution: {integrity: sha512-c0wdcekXtQvvn5Tsrk/+op/gUArrbWaFduBnTLP2l1cKLSQs4diMWjJw3m6A0DdzT8dAAX95KpkJ3qynCePbmw==} + '@rollup/rollup-android-arm-eabi@4.62.4': + resolution: {integrity: sha512-RrPokAb7dmbxFoeO3TloqHyOjgye8RkBhSqmp4aJMIex4c9r46ZstPnleDQOq1t46VOVjwIuwNogIqbodV1Vvg==} cpu: [arm] os: [android] - '@rollup/rollup-android-arm64@4.62.3': - resolution: {integrity: sha512-3YjElDdWN+qXAFbJ/CzPV+0wspLqh54k/I6GfdYtEJRqg7buSgc1yPM3B+93j1M4neobtkATHZTmxK2AMVGfnA==} + '@rollup/rollup-android-arm64@4.62.4': + resolution: {integrity: sha512-JKuJc+pnpks2pjy7L/N3v/cAkZxYlnmuZoD840ldbMI5KDbC4iO9NKwPKYdjYFCMAIIlBzYSFHxIJVYzRo2/8A==} cpu: [arm64] os: [android] - '@rollup/rollup-darwin-arm64@4.62.3': - resolution: {integrity: sha512-Pch2pFNOxxz1hTjypIdPyRTR6riiwRl84+VcN9djS680fw+Co1nAJINrdpqp7KV0NvyuU8ilZXZCjd7ykJl1GQ==} + '@rollup/rollup-darwin-arm64@4.62.4': + resolution: {integrity: sha512-krw5uS2STmvJ02x0uTXHbqQNuz+9eZ1iw+qXk9dmW2gvV4jV7O2hEoOnuhFrpOPiel1mBFtqbxYZZtC46hXLOw==} cpu: [arm64] os: [darwin] - '@rollup/rollup-darwin-x64@4.62.3': - resolution: {integrity: sha512-LEuncFUHFiF8t4yZVZvvZA1wk0pjAscRnsrn1EfTEmN4HXotBi2YtcnLRyaK6UbuczW7xZS5ES+81Rdz8Z0T6g==} + '@rollup/rollup-darwin-x64@4.62.4': + resolution: {integrity: sha512-wsTxtgApb4PrOsNJIm0FZ1h3WvCC+k9uxLJ4ad75hgoS4NiRes2SoJFlDAyMwiUY8IssDqGcHbXuN0sx1tfF1A==} cpu: [x64] os: [darwin] - '@rollup/rollup-freebsd-arm64@4.62.3': - resolution: {integrity: sha512-zvBUvsQUpOWALdDsk6qbS8bXf2VxmPisuudNDrY7x0p0jBdsoZl8HsHczIOgkQiZldmcacMKtBzpoGVNeIe2bQ==} + '@rollup/rollup-freebsd-arm64@4.62.4': + resolution: {integrity: sha512-GUOnQlyZe3yAXhWOtOMsn5Qkrv5E5mZXa0thbARWi5Ei2szlVXJFQhddZ4HbAzh8q92w5twp+CQvs/eFanz9YQ==} cpu: [arm64] os: [freebsd] - '@rollup/rollup-freebsd-x64@4.62.3': - resolution: {integrity: sha512-C2KmNrcSem/AMg984H/dev+si0lieQGdXdR/lYGJnuumXnFb9Y7QdiI62obFdLlxRYLBv4P0eUVIDbD4c1vVvw==} + '@rollup/rollup-freebsd-x64@4.62.4': + resolution: {integrity: sha512-/Y7f3QuxjzPKsjA/rfEDa3+0vXqyjmJ50Ln8dPpCmWkKTrUoWHG1cWhTqaAMLob2m2nESWuC7yGrREz019Ztqg==} cpu: [x64] os: [freebsd] - '@rollup/rollup-linux-arm-gnueabihf@4.62.3': - resolution: {integrity: sha512-ggXnsTAEzNQx74XpunRsiZ9aBZDsI7XIa0hm2nzR9f4WzH5/f/d73ZSDaC5ejJ8YLY4NW+V3wr0tjOaeCq8hqA==} + '@rollup/rollup-linux-arm-gnueabihf@4.62.4': + resolution: {integrity: sha512-81wiiX3v7aqy+T+bT61TJ78yJjRquqFFTTbAPt08imfQQzkPIW8t6aJbkTagtCCrXMNc9D66+geqlK7ydLPNqA==} cpu: [arm] os: [linux] libc: [glibc] - '@rollup/rollup-linux-arm-musleabihf@4.62.3': - resolution: {integrity: sha512-2vng+FlzNUhKZxtej3IUqJgbZoQk2M/dwQM20+ULV0R/E/8tr9/P6uEf2iiGIk4HL0zMKh5Jry7mUHdUOvyGgA==} + '@rollup/rollup-linux-arm-musleabihf@4.62.4': + resolution: {integrity: sha512-9kmDIvNZqdoHOBZgNtpTBeLWYO/LVipM3H/j62P8848/l/VPEQL6N3uxU9pvP1oZAsXyC2MEnFP3ovRjo7WYNQ==} cpu: [arm] os: [linux] libc: [musl] - '@rollup/rollup-linux-arm64-gnu@4.62.3': - resolution: {integrity: sha512-LLLFZKt4/Nraf9rxDkhiU8QVgLF4WmCkfr0L4fj0fPfIZFBib0DeiFk1hhaYKd03LFAFJcxHslhDFlNJLylf5Q==} + '@rollup/rollup-linux-arm64-gnu@4.62.4': + resolution: {integrity: sha512-CcnXHWnXg69g+DX5VWL3FHts3qMRN2uVEHX+BZvGLdd07/gXkn3ePjYtO1LDJvxkGKVHMclKBRa1QUTH+6toYQ==} cpu: [arm64] os: [linux] libc: [glibc] - '@rollup/rollup-linux-arm64-musl@4.62.3': - resolution: {integrity: sha512-WJkdQCvS9sWNOUBJZfQRKpZGFBztRzcowI+nndmflKgU4XY+3a420FgTOSKTsVqJbnzSxeT4vaJalpOaPo2YCQ==} + '@rollup/rollup-linux-arm64-musl@4.62.4': + resolution: {integrity: sha512-iFOibiHnTRuhrWLlRsOQFdZJJIa7S8OwkneJr4ocALP16u5yk6lWLINFwhHaEqBFMsKDUZofLkGos7+CPzGB3g==} cpu: [arm64] os: [linux] libc: [musl] - '@rollup/rollup-linux-loong64-gnu@4.62.3': - resolution: {integrity: sha512-PwHXCCS2n64/1Ot6rP1YEYA02MGYBcQlr8CSZZyrUG2O7NH6NklYmvr9v3Jy+5e/eDeNchc/ukmKJi9LuflMIQ==} + '@rollup/rollup-linux-loong64-gnu@4.62.4': + resolution: {integrity: sha512-XnWYMI7euHlb5a871xPja+Gm7DRCFU+FGRrtS2sMq9N8FvqtpagUy6gD4YOemC5MRk9xbh8+jYMEJbigFQwsgA==} cpu: [loong64] os: [linux] libc: [glibc] - '@rollup/rollup-linux-loong64-musl@4.62.3': - resolution: {integrity: sha512-vUjxINQu3RC8NZS3ykk1gN65gIz8pAopOq2HXuZhiIxHdx7TFvDG+jgrdSgInu1Eza4/Rfi2VzZgyIgEH4WOaw==} + '@rollup/rollup-linux-loong64-musl@4.62.4': + resolution: {integrity: sha512-qGDAlO0U8xedCcsdRm9oaoQY8DAx/QT7uIxJWhCdx0ceIWX783UC9QSYkdpzAe29wNiVfp24+bZdQmn49o45SQ==} cpu: [loong64] os: [linux] libc: [musl] - '@rollup/rollup-linux-ppc64-gnu@4.62.3': - resolution: {integrity: sha512-wzko4aJ13+0G3kGnviCg5gnXFKd40izKsrf2uOw12US4XqprkDrmwOpeW14aSNa37V8bfPcz5Fkob6LZ3BAPmA==} + '@rollup/rollup-linux-ppc64-gnu@4.62.4': + resolution: {integrity: sha512-ru4H6ezD7ysA5EiEK6qkkaEb4modH8CTej6kUy/gQi20u3kB3G7Zn8snXXkeJSCOFKG/rbPPtM/+9Wgas1961w==} cpu: [ppc64] os: [linux] libc: [glibc] - '@rollup/rollup-linux-ppc64-musl@4.62.3': - resolution: {integrity: sha512-8120ue0JUMSwy11stlwnfdX3pPd+WZYGCDBwEHWtIHi6pOpZmsEF5QKB7a/UN+XFdqvobxz98kv8RTqikyCEBw==} + '@rollup/rollup-linux-ppc64-musl@4.62.4': + resolution: {integrity: sha512-2W4MO5WQVJnbJaZdvDb9rhBDuFU1nKIepPFpJUBsTh2k1YY2g+ODViaWuyOAjQ5cOP7NvrvLzt3wvHOoiAvc7w==} cpu: [ppc64] os: [linux] libc: [musl] - '@rollup/rollup-linux-riscv64-gnu@4.62.3': - resolution: {integrity: sha512-XLFHnR3tXMjbOCh2vtVJHmxt+995uJsTERQyseFDRA0xxMxyTZPLa3OIUlyFaO4mF/Lu0FjmWHCuPXJT1n/IOg==} + '@rollup/rollup-linux-riscv64-gnu@4.62.4': + resolution: {integrity: sha512-+fxjfuoAmVMCYV5QyjoIpu0cp5DOiOTeqYFk1AVaxGr+/ravWLX89XfQmptsoWcaVy/TGf2hexzbUOrCQIL1CQ==} cpu: [riscv64] os: [linux] libc: [glibc] - '@rollup/rollup-linux-riscv64-musl@4.62.3': - resolution: {integrity: sha512-se6yXvNGMIl0f+RQzyh7XAmia8/9kplQx424wnG2w0C1oi6XgO6Y8otKhdXFHbHs88Ihavzmvh1NWjuovE76BQ==} + '@rollup/rollup-linux-riscv64-musl@4.62.4': + resolution: {integrity: sha512-jTn8JfHGL4djjFxPuM06LmNUJDsst2jeVlsd9OmIH6zc5sC9K6rIuO4YajXatLUpBmBKl6b35ro1QZocLi+tcA==} cpu: [riscv64] os: [linux] libc: [musl] - '@rollup/rollup-linux-s390x-gnu@4.62.3': - resolution: {integrity: sha512-gNoxRefktVIiGflpONuxWWXZAzIQG++z9qHO3xKwk4WdDMuQja3JHGfE1u0i3PfPDyvhypdk+WrgIJqLhGG7sg==} + '@rollup/rollup-linux-s390x-gnu@4.62.4': + resolution: {integrity: sha512-oCJCJL4pXsoDcP2QZ+JVlPTIRc6266zsIaeJJsWImmF7HO0W8nb6HuSgZlMWxJwaPf8ehbSw8yo0EUw925hKsA==} cpu: [s390x] os: [linux] libc: [glibc] - '@rollup/rollup-linux-x64-gnu@4.62.3': - resolution: {integrity: sha512-V4KtWtQfAFMU7+9/A/VDps/VI8CHd3cYz0L8sgJzz8qK7eY7wI4ruFD82UYIYvW9Z4DtlTfhQcsl4XyPHW5uSg==} + '@rollup/rollup-linux-x64-gnu@4.62.4': + resolution: {integrity: sha512-W69hukhZ3KKNRCaMIEzKvcFye42hh0FE1+YoYaf5+Ikacuftoco6yO/xouz0hc5d5W/s3yBro5jRiuEE/Q5vUw==} cpu: [x64] os: [linux] libc: [glibc] - '@rollup/rollup-linux-x64-musl@4.62.3': - resolution: {integrity: sha512-LBx9LYXvj2CBkMkjLdNAWLwH0MLMin7do2VcVo9kVPibGLkY0BQQut2fv7NVqkXqZ/CrAu9LqDHVV1xHCMpCPw==} + '@rollup/rollup-linux-x64-musl@4.62.4': + resolution: {integrity: sha512-qiXbGG2jkjXhzXpsFZSR2Xpb8DN/UaxYsbb/STbuR/6fpaDgRmmaq1B/LmtF2wQFOFOSsK2jdE0RZ3a0zHn4QA==} cpu: [x64] os: [linux] libc: [musl] - '@rollup/rollup-openbsd-x64@4.62.3': - resolution: {integrity: sha512-ABVf3Q0RCu7NcyCCOZQI0pJ3GuSdfSl8EXcy88QtdceIMIoCUdfhsJChZ64L9zVM2aJHjde1Bhn5uqSRcX9ySA==} + '@rollup/rollup-openbsd-x64@4.62.4': + resolution: {integrity: sha512-nWeM//hxv8mIo6jD7Hu4o48DVmV9pbV6gsKaWU+4NFyqHoPKwrkRiZGLKUhOBk8qNmDmpwFtPKg80Bo/Tn4xiQ==} cpu: [x64] os: [openbsd] - '@rollup/rollup-openharmony-arm64@4.62.3': - resolution: {integrity: sha512-+2Cy/ldweGBLlPIKsQLF8U5N44a0KDdbrk1rAjHOM9M2K+kGdIVjHLmmrZIcx+9Ny3ke/1JomCsDI1ocb11+sg==} + '@rollup/rollup-openharmony-arm64@4.62.4': + resolution: {integrity: sha512-s62SQ/vgsRSvMwDkOEfTqfgASF0f26ZNaQuTA6Aok5lrikf89yI2W0gFHvZb2Jpgc6N8JnOKZgCK2iciO3CsxQ==} cpu: [arm64] os: [openharmony] - '@rollup/rollup-win32-arm64-msvc@4.62.3': - resolution: {integrity: sha512-dtZvzc8BedpSaFNy75x6uiWwAGTH+aZHDtdrqP6qk+WcLJrfti6sGje1ZJ9UxyzDLF23d/mV+PaMwuC0hL7UVA==} + '@rollup/rollup-win32-arm64-msvc@4.62.4': + resolution: {integrity: sha512-J6wGf8TVGbXJq+HH+ttTvrcfNKPbuZecV6KT1B8I18BC5IURUh5kl4Yl5OEP5eFIUoI5BWxCsyYMhFsDx8kekw==} cpu: [arm64] os: [win32] - '@rollup/rollup-win32-ia32-msvc@4.62.3': - resolution: {integrity: sha512-Rj8Ra4noo+aYy7sKBggCx0407mws34kAb1ySyWuq5DAtFBQdkSwnsjCgPrhPe9cvgBKZIukpE+CVHvORCS93kQ==} + '@rollup/rollup-win32-ia32-msvc@4.62.4': + resolution: {integrity: sha512-zmfrQd/0wu6oJs8Vq8KwY/YtsKSsLtKe/HwAP4Wqy8LhWjeT55fHRAkOhYQ12wI3ayS4Tt12d5CDRD7N96SAYQ==} cpu: [ia32] os: [win32] - '@rollup/rollup-win32-x64-gnu@4.62.3': - resolution: {integrity: sha512-vp7N084ew/odXn2gi/mzm9mUkQu9l6AiN6dt4IeUM2Uvm9o+cVmP+YkqbMOteLbiGgqBBlJZjIMYVCfOOIVbVQ==} + '@rollup/rollup-win32-x64-gnu@4.62.4': + resolution: {integrity: sha512-qPzHqdj9rfUD+w79dtE07zi/kFwKyCJqplp5K5ygeLTp7jLpAoc16OAH39HSmRC9UpozaecsleI8uAdEj6v2yw==} cpu: [x64] os: [win32] - '@rollup/rollup-win32-x64-msvc@4.62.3': - resolution: {integrity: sha512-MOG/3gTOn4Fwf574RVOaY61I5o6P90legkFADiTyn1hyjNydT+cerU2rLUwPdZkKKyJ+iT+K9p7WXK4LM1Ka6g==} + '@rollup/rollup-win32-x64-msvc@4.62.4': + resolution: {integrity: sha512-zD6NdeWEByGE9QF9vCrlJ5YQB4oq9q91kPZS37Jwj5hOkvR1lTBSpsKhKDw4IJtbQ35LsTS1HD9DZYGKIshU1Q==} cpu: [x64] os: [win32] @@ -1197,13 +1208,13 @@ packages: '@standard-schema/utils@0.3.0': resolution: {integrity: sha512-e7Mew686owMaPJVNNLs55PUvgz371nKgwsc4vxE49zsODpJEnxgxRo2y/OKrqueavXgZNMDVj3DdHFlaSAeU8g==} - '@tabler/icons-react@3.45.0': - resolution: {integrity: sha512-t/AuKs7ALMDDTY+B9IvfZnlO0mbLlP/lJxP/HnGC49QkM8mCsTN38kYyxjXxgrb1+TeK53ioVBJqIV7n/eysXQ==} + '@tabler/icons-react@3.46.0': + resolution: {integrity: sha512-CCm7xJWhDT2PH4ZIFkP6AgYKtVhq0gpYkjUN+GVh1AzmIQaa77OW0bQPBPQiTE0PsXMR9oSxFqA3qBglzPyrVQ==} peerDependencies: react: '>= 16' - '@tabler/icons@3.45.0': - resolution: {integrity: sha512-jiATwV8+zGYLTZ7gMLGivCic+KtsMZXcDmufIG8umlLxoHhI6902hGYIEt0Oa9Y9SXblNzUlrisHm5jOFMxOQA==} + '@tabler/icons@3.46.0': + resolution: {integrity: sha512-f2RYFl3fzPwj5WO82x6en0dmkjefxEfOm16D1ByM6cj/McNiwOkL4VaPUoP9VVIrXAD9WnTSVFr70px703b//A==} '@tanstack/query-core@5.101.4': resolution: {integrity: sha512-gNwcvOJcRbLWPOLG/2OBm+zM+Yv+MKsXKEOWC57USuZDEsI71hEErQsiEGx5wX9rzWWkfwM0fVSPoiIFSsxfiw==} @@ -1281,19 +1292,19 @@ packages: '@types/json-schema@7.0.15': resolution: {integrity: sha512-5+fP8P8MFNC+AyZCDxrB2pkZFPGzqQWUzpSeuuVLvm8VMcorNYavBqoFcxK8bQz4Qsbn4oUEEem4wDLfcysGHA==} - '@types/lodash@4.17.24': - resolution: {integrity: sha512-gIW7lQLZbue7lRSWEFql49QJJWThrTFFeIMJdp3eH4tKoxm1OvEPg02rm4wCCSHS0cL3/Fizimb35b7k8atwsQ==} + '@types/lodash@4.17.25': + resolution: {integrity: sha512-+K1NIO8I+F9/wNulfVvu23QYd0Pe9/OCqRrim4NoYIf1VoEDL90Ve4ClzpyqBLc7NpGGWRvYNCKZ1BE/Jpf8dQ==} '@types/node@26.0.1': resolution: {integrity: sha512-fc3KiUoBt6kie0N9bIW3E47vZsuaMf0PM2AaUpLCLT0s/LvX1nxAim6Fc049cNxODPpGm6qRAuUOB86SkRuPQw==} - '@types/react-dom@19.2.3': - resolution: {integrity: sha512-jp2L/eY6fn+KgVVQAOqYItbF0VY/YApe5Mz2F0aykSO8gx31bYCZyvSeYxCHKvzHG5eZjc+zyaS5BrBWya2+kQ==} + '@types/react-dom@19.2.4': + resolution: {integrity: sha512-Bsc+QHgp+P/F02XDzNCY9jnZNCUuLki36KT7VKrTXXLdHf+vHMNZnW1rVu5DNW/rCK+fya3DATySbLM4yhtKUw==} peerDependencies: '@types/react': ^19.2.0 - '@types/react@19.2.17': - resolution: {integrity: sha512-MXfmqaVPEVgkBT/aY0aGCkRWWtByiYQXo3xdQ8r5RzuFrPiRn8Gar2tQdXSUQ2GKV3bkXckek89V8wQBY2Q/Aw==} + '@types/react@19.2.18': + resolution: {integrity: sha512-AnzbBERsrLKtk2XSfTbYRLjQPdy116Sty4q+T+Bp3IC4l6jNBvreVPAHmpq9qhXQM7CXZPjLVmGMw9sy+hxQ3w==} '@types/resolve@1.20.2': resolution: {integrity: sha512-60BCwRFOZCQhDncwQdxxeOEEkbc5dIMccYLwbxsS4TUNeVECQ/pBJ0j09mrHOl/JJvpRPGwO9SvE4nR2Nb/a4Q==} @@ -1313,63 +1324,63 @@ packages: '@types/yargs@17.0.35': resolution: {integrity: sha512-qUHkeCyQFxMXg79wQfTtfndEC+N9ZZg76HJftDJp+qH2tV7Gj4OJi7l+PiWwJ+pWtW8GwSmqsDj/oymhrTWXjg==} - '@typescript-eslint/eslint-plugin@8.65.0': - resolution: {integrity: sha512-IEgob78X12rHpUmtcwFsXhZdVGJtwTVP8FiCLZkR6GlYVrl2PcuB+KhCE5BlVC/eQpQnu8WXRtkHZuPar+gCRA==} + '@typescript-eslint/eslint-plugin@8.66.0': + resolution: {integrity: sha512-p088eaGrzYz1s+7cov0aMOCkNGTJlVxF4jgubf28c8L0Cv9Rloj8YBHnv4hXLq6IIEE1AsjNWavO+k+8kP2Y0A==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} peerDependencies: - '@typescript-eslint/parser': ^8.65.0 + '@typescript-eslint/parser': ^8.66.0 eslint: ^8.57.0 || ^9.0.0 || ^10.0.0 typescript: '>=4.8.4 <6.1.0' - '@typescript-eslint/parser@8.65.0': - resolution: {integrity: sha512-CZ4nMxWwgu1HEEFNkeaCptra9QCtkmKdgf3sWh1rl1trIhmxLilgTV4cwcbQ4wemnT4sWQN8CaKOmdYx+g2gMA==} + '@typescript-eslint/parser@8.66.0': + resolution: {integrity: sha512-X6ypGChaWYk6PBtUg2BwuTZEFFcHJAtGTVJ9/lCTOufhZ4i9fNolQNnktq+kkMCwMj7V8Svsq7+TxSDslmhE0g==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} peerDependencies: eslint: ^8.57.0 || ^9.0.0 || ^10.0.0 typescript: '>=4.8.4 <6.1.0' - '@typescript-eslint/project-service@8.65.0': - resolution: {integrity: sha512-SxnPhbTsGahizDgbu7oqFH/xVtzIqMd/s+WtnSxNxJZJpLbdT5IPdzg8EZxO3+PoKahXmwJLeNQOpKJb3/bi7Q==} + '@typescript-eslint/project-service@8.66.0': + resolution: {integrity: sha512-7MthGPTt4BP69lSryqpqq8HQqxuzynssckL/jyDyk3+TNMQ3y2jFWkptCrktWvBrP+EH787Nl5N5Qpw7WZg+5g==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} peerDependencies: typescript: '>=4.8.4 <6.1.0' - '@typescript-eslint/scope-manager@8.65.0': - resolution: {integrity: sha512-Esbl8OSYiVxBokYgWPf7VVWg/BE798wXhimnn9ML9Pt5qoDf8bfQlgjlKXR/k98+AcNzlLKYrpCcrcuZ9DZLgg==} + '@typescript-eslint/scope-manager@8.66.0': + resolution: {integrity: sha512-8TGcH25j9zqJ/IULB/ppyhRvxA8QYfFEZ7nfbg6/BN9spDgb8fPWQXlE5l8TWBL50EtUx007uZ1o9VOwrq2/9g==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} - '@typescript-eslint/tsconfig-utils@8.65.0': - resolution: {integrity: sha512-j6GzGqCiRdA7Qhur2VVmKZAkBLfnHFQfx4TaJGL9RMveZqCo48jSHHO0DTgizEnGhtWnqmbtCUSrqSkdiY/0Hg==} + '@typescript-eslint/tsconfig-utils@8.66.0': + resolution: {integrity: sha512-9D5gLYZG4rOjcoag8MQ/fWI8WqA9wcPDyOGyWtWFhvM1lHRbliqUSPIY5J3zqCU1tvSwzXxnnjhQhz5Ne7mJ4g==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} peerDependencies: typescript: '>=4.8.4 <6.1.0' - '@typescript-eslint/type-utils@8.65.0': - resolution: {integrity: sha512-YjaZ7PRI5qY7ax2L3PbvX0rRyGtipAReCWs0mhhDBHjH/vl0g0BonaGXrKdKpMbIIsMIwDgbk/xzkBTyAltS5g==} + '@typescript-eslint/type-utils@8.66.0': + resolution: {integrity: sha512-LG2dWfjZQQp0ADtAu/EWJVayefGL2UEZ3CDeI44D9v3rXB/WYUqE/jpO28KrEKul5AySrmI+Zh1v6v+xW2U9+g==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} peerDependencies: eslint: ^8.57.0 || ^9.0.0 || ^10.0.0 typescript: '>=4.8.4 <6.1.0' - '@typescript-eslint/types@8.65.0': - resolution: {integrity: sha512-JSSwWNy+H0E/01jJEM+hrX6N0OFDzFzeIhHFSAS01tlVaevpG8cFyYRPhS5yjGOvBUx3sqQHVMjCL1CAZZMxBg==} + '@typescript-eslint/types@8.66.0': + resolution: {integrity: sha512-H6gcYaSDOyvL3AD/jHUtUFo2jqGgn/F6nuyuZSu0QTesxL+cP4dQoIMrODRofuJC09g64+WgZ6tE19Y1N2YIFQ==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} - '@typescript-eslint/typescript-estree@8.65.0': - resolution: {integrity: sha512-JboAE2swaYt4tb1fHhHTABE2K+OLy09XfcTbhnk4Pw96f9dd2e9iYsJ28gBggHlo5z5x1rkyWvcPoTuNTd4oGg==} + '@typescript-eslint/typescript-estree@8.66.0': + resolution: {integrity: sha512-8/x4INiiQb10jGgXYD7116/zQ+OL84ZIFn0za68wwFHCanT/VLbBEroWht8RV8fn0/ZCAoazHLQgwUC0UQcDfg==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} peerDependencies: typescript: '>=4.8.4 <6.1.0' - '@typescript-eslint/utils@8.65.0': - resolution: {integrity: sha512-gXiwIHsYreboxeJucHKPvgwl7dXt50mF8s1/c00cP/WoVTyWKFdtfhRWwZiXYFU5H2O8vVoSLNrexFZjYS/SGA==} + '@typescript-eslint/utils@8.66.0': + resolution: {integrity: sha512-jasearZPolBw5NJNYGMwxzHMF83niVWmMU1VdHzG1CyfI2VS7f7nZltnKtHcg20hW+7Uo5GfK4MeDPoU3qI8EA==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} peerDependencies: eslint: ^8.57.0 || ^9.0.0 || ^10.0.0 typescript: '>=4.8.4 <6.1.0' - '@typescript-eslint/visitor-keys@8.65.0': - resolution: {integrity: sha512-8C71BQkGjiMmXtop7pHVJu1l2NNShFdkCyD6a2ezzs5vU/L3LRtb69EtcteFwz0mYMPzIgOw0n6OV4VBUWZd7A==} + '@typescript-eslint/visitor-keys@8.66.0': + resolution: {integrity: sha512-dkKR8q+lKciskj1Y3vthHktl+3cMLWGyVUP23bRiPZ5O9BRT++4EqDDV+TVeIKBL1VXVEqrJlz8MYbcnvJcAlg==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} '@uiw/codemirror-extensions-basic-setup@4.25.11': @@ -1664,9 +1675,9 @@ packages: brace-expansion@2.1.1: resolution: {integrity: sha512-WR1cURNjuvBLMZBMbqM0UoE+WAfdUcEV1ccD8PVBVOI+Z3ND4+SZbN8RsfT2bMuG1qwz5RFvPukSZm5fF2D5eA==} - brace-expansion@5.0.6: - resolution: {integrity: sha512-kLpxurY4Z4r9sgMsyG0Z9uzsBlgiU/EFKhj/h91/8yHu0edo7XuixOIH3VcJ8kkxs6/jPzoI6U9Vj3WqbMQ94g==} - engines: {node: 18 || 20 || >=22} + brace-expansion@5.0.9: + resolution: {integrity: sha512-ScQ4IuvIEF1TMlP7Zt+vjJ//9zlPb2SDcxWxM3bk8s6t6GGdJ7KO1dCcTidOPJKePW30LE/2cT7wCyPho9/Wxg==} + engines: {node: 20 || >=22} braces@3.0.3: resolution: {integrity: sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==} @@ -2264,8 +2275,8 @@ packages: resolution: {integrity: sha512-hsBTNUqQTDwkWtcdYI2i06Y/nUBEsNEDJKjWdigLvegy8kDuJAS8uRlpkkcQpyEXL0Z/pjDy5HBmMjRCJ2gq+g==} engines: {node: '>= 4'} - ignore@7.0.5: - resolution: {integrity: sha512-Hs59xBNfUIunMFgWAbGX5cq6893IbWg4KnrjbYwX3tx0ztorVgTDA6B2sxf8ejHJ4wz8BqGUMYlnzNBer5NvGg==} + ignore@7.0.6: + resolution: {integrity: sha512-BAg6QkE8W+TuQLrrw0Ugr7HegXduRuuj8/ti2kSOc+jz1dmx8/WNcjr6XGnq5YpDWxFwwaavqD0+jIUOKelTsw==} engines: {node: '>= 4'} immer@11.1.8: @@ -2659,8 +2670,8 @@ packages: resolution: {integrity: sha512-I9jwMn07Sy/IwOj3zVkVik2JTvgpaykDZEigL6Rx6N9LbMywwUSMtxET+7lVoDLLd3O3IXwJwvuuns8UB/HeAg==} engines: {node: '>=4'} - minimatch@10.2.5: - resolution: {integrity: sha512-MULkVLfKGYDFYejP07QOurDLLQpcjk7Fw+7jXS2R2czRQzR56yHRveU5NDJEOviH+hETZKSkIk5c+T23GjFUMg==} + minimatch@10.2.6: + resolution: {integrity: sha512-vpLQEs+VLCr1nU0BXS07maYoFwlDAH0gngQuuttxIwutDFEMHq2blX+8vpgxDdK3J1PwjCJiep77OitTZ4Ll1A==} engines: {node: 18 || 20 || >=22} minimatch@3.1.5: @@ -2688,6 +2699,11 @@ packages: engines: {node: ^10 || ^12 || ^13.7 || ^14 || >=15.0.1} hasBin: true + nanoid@3.3.18: + resolution: {integrity: sha512-DTg4MJbGMWkfi6VZFdNt2/caMbQy4Ou+Op/hJQvGEWcnVfoA1QA+xzRKAzw9jD6+GVOOeYr/mIcuDSdug6F6+w==} + engines: {node: ^10 || ^12 || ^13.7 || ^14 || >=15.0.1} + hasBin: true + napi-postinstall@0.3.4: resolution: {integrity: sha512-PHI5f1O0EP5xJ9gQmFGMS6IZcrVvTjpXjz7Na41gTE7eE2hK11lg04CECCYEEjdc17EV4DO+fkGEtt7TpTaTiQ==} engines: {node: ^12.20.0 || ^14.18.0 || >=16.0.0} @@ -2699,8 +2715,8 @@ packages: neo-async@2.6.2: resolution: {integrity: sha512-Yd3UES5mWCSqR+qNT93S3UoYUkqAZ9lLg8a7g9rimsWmYGK8cVToA4/sF3RrshdyV3sAGMXVUmpMYOw+dLpOuw==} - nock@14.0.16: - resolution: {integrity: sha512-8r4KEc6nT1D/fdLD/R1BO1CPaVEL8o40u/guFRJlXabN7vr3RmMqyjsY5Krt0nMwhsOAwXQ/mtN5vy5Jh3aErg==} + nock@14.0.17: + resolution: {integrity: sha512-EjRr1weMa4ALQX35AgZTEnP+weJJjlW1KGDiNM2IQC2069YDHas4f4B4UUYR+TTLyKWxJvOz2wObDKQs/LNreA==} engines: {node: '>=18.20.0 <20 || >=20.12.1'} node-fetch@2.7.0: @@ -2871,6 +2887,10 @@ packages: resolution: {integrity: sha512-g50586zr4bZmwFiTlflMu8E0bDTb5I5gertgwAKmsdUlTQIhZtunzUlD1WSzwcVWPoAVpsrA6vlfCD7oXvRwgg==} engines: {node: ^10 || ^12 || >=14} + postcss@8.5.26: + resolution: {integrity: sha512-u82N74LFzG8ca+dD8puPnplTXoGH4fTPpVGuIbt36G3qvNlkvfD0lEAZSxaly3KX8TS/L1A1gsCEmvKmBcVbkQ==} + engines: {node: ^10 || ^12 || >=14} + prelude-ls@1.2.1: resolution: {integrity: sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==} engines: {node: '>= 0.8.0'} @@ -2974,15 +2994,15 @@ packages: '@types/react': optional: true - react-router-dom@7.18.1: - resolution: {integrity: sha512-KaZh+X/6UtEp28x51AUYZDMg9NGoz2ja3dNHa+ta/tk40vCzKhQ/RypCWBMLbmDr6//E24Vv5uPsrqXFozdkAg==} + react-router-dom@7.18.2: + resolution: {integrity: sha512-AIKJ/jgGlFb3EbfCXk5Gzshiwt+l3mqbCrNjmEWMMjqQxNJ3svBa6bgzFyCC2Sw3RA0VWF1kg3uQf2OFhxb8hw==} engines: {node: '>=20.0.0'} peerDependencies: react: '>=18' react-dom: '>=18' - react-router@7.18.1: - resolution: {integrity: sha512-GDLgg3i3uM0aeJO3Fm+TCS+sDQ7gu12T6x0qdTEzcwqEfleci7JwugVNIF3U//0FWKnJT7ptG+20B2jfDqnZAg==} + react-router@7.18.2: + resolution: {integrity: sha512-aUVMjFm3GAPTTZL7oYr5E7ETiqfQCHRLH+B+5afnICvf0r7kkK4eR6SMuwbSTJw/7t+12khT/Kahij49fqOCIg==} engines: {node: '>=20.0.0'} peerDependencies: react: '>=18' @@ -3053,8 +3073,8 @@ packages: peerDependencies: rollup: ^1.0.0 || ^2.0.0 || ^3.0.0 || ^4.0.0 - rollup@4.62.3: - resolution: {integrity: sha512-Gu0c0iH9FzgX1L1t7ByIbbS3Vmdz+6KHm/EsqmmC71gUQ82yvZRkTK6XzrFObSka91WUVdynqp6nsfilzr5k6Q==} + rollup@4.62.4: + resolution: {integrity: sha512-RXOqwaPsBGjMNMa4sQjDjHieHEZDFoj/Rdr46l2MU5DfEs16wHJPC2RPTPHWhNl+M3aI472LLqFkFKut4SblOg==} engines: {node: '>=18.0.0', npm: '>=8.0.0'} hasBin: true @@ -3230,8 +3250,8 @@ packages: resolution: {integrity: sha512-eNRKgb3z66Yp3D2CixVujOUvXLFUTij/zVnV8KRyvFdQwpz7I5DS8UfRkTeLzb64u+dkzDSdelE24izu+zSSUg==} engines: {node: ^14.18.0 || >=16.0.0} - tabbable@6.4.0: - resolution: {integrity: sha512-05PUHKSNE8ou2dwIxTngl4EzcnsCDZGJ/iCLtDflR/SHB/ny14rXc+qU5P4mG9JkusiV7EivzY9Mhm55AzAvCg==} + tabbable@6.5.0: + resolution: {integrity: sha512-wieBHXygIm7OyQOu5hQlkk62/WyCFYGlWg7L6/ZCUZwx0o398Zkn4pVmMyfYhfMG8kGrj/Krt8eIk6UKC6VzwA==} tagged-tag@1.0.0: resolution: {integrity: sha512-yEFYrVhod+hdNyx7g5Bnkkb0G6si8HJurOoOEgC8B/O0uXLHlaey/65KRv6cuWBNhBgHKAROVpc7QyYqE5gFng==} @@ -3627,20 +3647,20 @@ snapshots: '@babel/compat-data@7.29.7': {} - '@babel/core@7.29.7': + '@babel/core@7.29.7(supports-color@8.1.1)': dependencies: '@babel/code-frame': 7.29.7 '@babel/generator': 7.29.7 '@babel/helper-compilation-targets': 7.29.7 - '@babel/helper-module-transforms': 7.29.7(@babel/core@7.29.7) + '@babel/helper-module-transforms': 7.29.7(@babel/core@7.29.7(supports-color@8.1.1))(supports-color@8.1.1) '@babel/helpers': 7.29.7 '@babel/parser': 7.29.7 '@babel/template': 7.29.7 - '@babel/traverse': 7.29.7 + '@babel/traverse': 7.29.7(supports-color@8.1.1) '@babel/types': 7.29.7 '@jridgewell/remapping': 2.3.5 convert-source-map: 2.0.0 - debug: 4.4.3 + debug: 4.4.3(supports-color@8.1.1) gensync: 1.0.0-beta.2 json5: 2.2.3 semver: 6.3.1 @@ -3665,19 +3685,19 @@ snapshots: '@babel/helper-globals@7.29.7': {} - '@babel/helper-module-imports@7.29.7': + '@babel/helper-module-imports@7.29.7(supports-color@8.1.1)': dependencies: - '@babel/traverse': 7.29.7 + '@babel/traverse': 7.29.7(supports-color@8.1.1) '@babel/types': 7.29.7 transitivePeerDependencies: - supports-color - '@babel/helper-module-transforms@7.29.7(@babel/core@7.29.7)': + '@babel/helper-module-transforms@7.29.7(@babel/core@7.29.7(supports-color@8.1.1))(supports-color@8.1.1)': dependencies: - '@babel/core': 7.29.7 - '@babel/helper-module-imports': 7.29.7 + '@babel/core': 7.29.7(supports-color@8.1.1) + '@babel/helper-module-imports': 7.29.7(supports-color@8.1.1) '@babel/helper-validator-identifier': 7.29.7 - '@babel/traverse': 7.29.7 + '@babel/traverse': 7.29.7(supports-color@8.1.1) transitivePeerDependencies: - supports-color @@ -3698,99 +3718,99 @@ snapshots: dependencies: '@babel/types': 7.29.7 - '@babel/plugin-syntax-async-generators@7.8.4(@babel/core@7.29.7)': + '@babel/plugin-syntax-async-generators@7.8.4(@babel/core@7.29.7(supports-color@8.1.1))': dependencies: - '@babel/core': 7.29.7 + '@babel/core': 7.29.7(supports-color@8.1.1) '@babel/helper-plugin-utils': 7.29.7 - '@babel/plugin-syntax-bigint@7.8.3(@babel/core@7.29.7)': + '@babel/plugin-syntax-bigint@7.8.3(@babel/core@7.29.7(supports-color@8.1.1))': dependencies: - '@babel/core': 7.29.7 + '@babel/core': 7.29.7(supports-color@8.1.1) '@babel/helper-plugin-utils': 7.29.7 - '@babel/plugin-syntax-class-properties@7.12.13(@babel/core@7.29.7)': + '@babel/plugin-syntax-class-properties@7.12.13(@babel/core@7.29.7(supports-color@8.1.1))': dependencies: - '@babel/core': 7.29.7 + '@babel/core': 7.29.7(supports-color@8.1.1) '@babel/helper-plugin-utils': 7.29.7 - '@babel/plugin-syntax-class-static-block@7.14.5(@babel/core@7.29.7)': + '@babel/plugin-syntax-class-static-block@7.14.5(@babel/core@7.29.7(supports-color@8.1.1))': dependencies: - '@babel/core': 7.29.7 + '@babel/core': 7.29.7(supports-color@8.1.1) '@babel/helper-plugin-utils': 7.29.7 - '@babel/plugin-syntax-import-attributes@7.29.7(@babel/core@7.29.7)': + '@babel/plugin-syntax-import-attributes@7.29.7(@babel/core@7.29.7(supports-color@8.1.1))': dependencies: - '@babel/core': 7.29.7 + '@babel/core': 7.29.7(supports-color@8.1.1) '@babel/helper-plugin-utils': 7.29.7 - '@babel/plugin-syntax-import-meta@7.10.4(@babel/core@7.29.7)': + '@babel/plugin-syntax-import-meta@7.10.4(@babel/core@7.29.7(supports-color@8.1.1))': dependencies: - '@babel/core': 7.29.7 + '@babel/core': 7.29.7(supports-color@8.1.1) '@babel/helper-plugin-utils': 7.29.7 - '@babel/plugin-syntax-json-strings@7.8.3(@babel/core@7.29.7)': + '@babel/plugin-syntax-json-strings@7.8.3(@babel/core@7.29.7(supports-color@8.1.1))': dependencies: - '@babel/core': 7.29.7 + '@babel/core': 7.29.7(supports-color@8.1.1) '@babel/helper-plugin-utils': 7.29.7 - '@babel/plugin-syntax-jsx@7.29.7(@babel/core@7.29.7)': + '@babel/plugin-syntax-jsx@7.29.7(@babel/core@7.29.7(supports-color@8.1.1))': dependencies: - '@babel/core': 7.29.7 + '@babel/core': 7.29.7(supports-color@8.1.1) '@babel/helper-plugin-utils': 7.29.7 - '@babel/plugin-syntax-logical-assignment-operators@7.10.4(@babel/core@7.29.7)': + '@babel/plugin-syntax-logical-assignment-operators@7.10.4(@babel/core@7.29.7(supports-color@8.1.1))': dependencies: - '@babel/core': 7.29.7 + '@babel/core': 7.29.7(supports-color@8.1.1) '@babel/helper-plugin-utils': 7.29.7 - '@babel/plugin-syntax-nullish-coalescing-operator@7.8.3(@babel/core@7.29.7)': + '@babel/plugin-syntax-nullish-coalescing-operator@7.8.3(@babel/core@7.29.7(supports-color@8.1.1))': dependencies: - '@babel/core': 7.29.7 + '@babel/core': 7.29.7(supports-color@8.1.1) '@babel/helper-plugin-utils': 7.29.7 - '@babel/plugin-syntax-numeric-separator@7.10.4(@babel/core@7.29.7)': + '@babel/plugin-syntax-numeric-separator@7.10.4(@babel/core@7.29.7(supports-color@8.1.1))': dependencies: - '@babel/core': 7.29.7 + '@babel/core': 7.29.7(supports-color@8.1.1) '@babel/helper-plugin-utils': 7.29.7 - '@babel/plugin-syntax-object-rest-spread@7.8.3(@babel/core@7.29.7)': + '@babel/plugin-syntax-object-rest-spread@7.8.3(@babel/core@7.29.7(supports-color@8.1.1))': dependencies: - '@babel/core': 7.29.7 + '@babel/core': 7.29.7(supports-color@8.1.1) '@babel/helper-plugin-utils': 7.29.7 - '@babel/plugin-syntax-optional-catch-binding@7.8.3(@babel/core@7.29.7)': + '@babel/plugin-syntax-optional-catch-binding@7.8.3(@babel/core@7.29.7(supports-color@8.1.1))': dependencies: - '@babel/core': 7.29.7 + '@babel/core': 7.29.7(supports-color@8.1.1) '@babel/helper-plugin-utils': 7.29.7 - '@babel/plugin-syntax-optional-chaining@7.8.3(@babel/core@7.29.7)': + '@babel/plugin-syntax-optional-chaining@7.8.3(@babel/core@7.29.7(supports-color@8.1.1))': dependencies: - '@babel/core': 7.29.7 + '@babel/core': 7.29.7(supports-color@8.1.1) '@babel/helper-plugin-utils': 7.29.7 - '@babel/plugin-syntax-private-property-in-object@7.14.5(@babel/core@7.29.7)': + '@babel/plugin-syntax-private-property-in-object@7.14.5(@babel/core@7.29.7(supports-color@8.1.1))': dependencies: - '@babel/core': 7.29.7 + '@babel/core': 7.29.7(supports-color@8.1.1) '@babel/helper-plugin-utils': 7.29.7 - '@babel/plugin-syntax-top-level-await@7.14.5(@babel/core@7.29.7)': + '@babel/plugin-syntax-top-level-await@7.14.5(@babel/core@7.29.7(supports-color@8.1.1))': dependencies: - '@babel/core': 7.29.7 + '@babel/core': 7.29.7(supports-color@8.1.1) '@babel/helper-plugin-utils': 7.29.7 - '@babel/plugin-syntax-typescript@7.29.7(@babel/core@7.29.7)': + '@babel/plugin-syntax-typescript@7.29.7(@babel/core@7.29.7(supports-color@8.1.1))': dependencies: - '@babel/core': 7.29.7 + '@babel/core': 7.29.7(supports-color@8.1.1) '@babel/helper-plugin-utils': 7.29.7 - '@babel/plugin-transform-react-jsx-self@7.29.7(@babel/core@7.29.7)': + '@babel/plugin-transform-react-jsx-self@7.29.7(@babel/core@7.29.7(supports-color@8.1.1))': dependencies: - '@babel/core': 7.29.7 + '@babel/core': 7.29.7(supports-color@8.1.1) '@babel/helper-plugin-utils': 7.29.7 - '@babel/plugin-transform-react-jsx-source@7.29.7(@babel/core@7.29.7)': + '@babel/plugin-transform-react-jsx-source@7.29.7(@babel/core@7.29.7(supports-color@8.1.1))': dependencies: - '@babel/core': 7.29.7 + '@babel/core': 7.29.7(supports-color@8.1.1) '@babel/helper-plugin-utils': 7.29.7 '@babel/runtime@7.29.7': {} @@ -3801,7 +3821,7 @@ snapshots: '@babel/parser': 7.29.7 '@babel/types': 7.29.7 - '@babel/traverse@7.29.7': + '@babel/traverse@7.29.7(supports-color@8.1.1)': dependencies: '@babel/code-frame': 7.29.7 '@babel/generator': 7.29.7 @@ -3809,7 +3829,7 @@ snapshots: '@babel/parser': 7.29.7 '@babel/template': 7.29.7 '@babel/types': 7.29.7 - debug: 4.4.3 + debug: 4.4.3(supports-color@8.1.1) transitivePeerDependencies: - supports-color @@ -3824,20 +3844,20 @@ snapshots: dependencies: '@codemirror/language': 6.12.4 '@codemirror/state': 6.7.1 - '@codemirror/view': 6.43.6 + '@codemirror/view': 6.43.8 '@lezer/common': 1.5.2 '@codemirror/commands@6.10.4': dependencies: '@codemirror/language': 6.12.4 '@codemirror/state': 6.7.1 - '@codemirror/view': 6.43.6 + '@codemirror/view': 6.43.8 '@lezer/common': 1.5.2 '@codemirror/language@6.12.4': dependencies: '@codemirror/state': 6.7.1 - '@codemirror/view': 6.43.6 + '@codemirror/view': 6.43.8 '@lezer/common': 1.5.2 '@lezer/highlight': 1.2.3 '@lezer/lr': 1.4.10 @@ -3846,13 +3866,13 @@ snapshots: '@codemirror/lint@6.9.7': dependencies: '@codemirror/state': 6.7.1 - '@codemirror/view': 6.43.6 + '@codemirror/view': 6.43.8 crelt: 1.0.7 '@codemirror/search@6.7.1': dependencies: '@codemirror/state': 6.7.1 - '@codemirror/view': 6.43.6 + '@codemirror/view': 6.43.8 crelt: 1.0.7 '@codemirror/state@6.7.1': @@ -3863,10 +3883,10 @@ snapshots: dependencies: '@codemirror/language': 6.12.4 '@codemirror/state': 6.7.1 - '@codemirror/view': 6.43.6 + '@codemirror/view': 6.43.8 '@lezer/highlight': 1.2.3 - '@codemirror/view@6.43.6': + '@codemirror/view@6.43.8': dependencies: '@codemirror/state': 6.7.1 crelt: 1.0.7 @@ -3987,23 +4007,23 @@ snapshots: '@esbuild/win32-x64@0.25.12': optional: true - '@eslint-community/eslint-utils@4.9.1(eslint@9.39.5)': + '@eslint-community/eslint-utils@4.10.1(eslint@9.39.5(supports-color@8.1.1))': dependencies: - eslint: 9.39.5 + eslint: 9.39.5(supports-color@8.1.1) eslint-visitor-keys: 3.4.3 '@eslint-community/regexpp@4.12.2': {} - '@eslint/compat@1.4.1(eslint@9.39.5)': + '@eslint/compat@2.1.0(eslint@9.39.5(supports-color@8.1.1))': dependencies: - '@eslint/core': 0.17.0 + '@eslint/core': 1.2.1 optionalDependencies: - eslint: 9.39.5 + eslint: 9.39.5(supports-color@8.1.1) - '@eslint/config-array@0.21.2': + '@eslint/config-array@0.21.2(supports-color@8.1.1)': dependencies: '@eslint/object-schema': 2.1.7 - debug: 4.4.3 + debug: 4.4.3(supports-color@8.1.1) minimatch: 3.1.5 transitivePeerDependencies: - supports-color @@ -4016,10 +4036,14 @@ snapshots: dependencies: '@types/json-schema': 7.0.15 - '@eslint/eslintrc@3.3.6': + '@eslint/core@1.2.1': + dependencies: + '@types/json-schema': 7.0.15 + + '@eslint/eslintrc@3.3.6(supports-color@8.1.1)': dependencies: ajv: 6.15.0 - debug: 4.4.3 + debug: 4.4.3(supports-color@8.1.1) espree: 10.4.0 globals: 14.0.0 ignore: 5.3.2 @@ -4048,19 +4072,19 @@ snapshots: '@floating-ui/core': 1.8.0 '@floating-ui/utils': 0.2.12 - '@floating-ui/react-dom@2.1.8(react-dom@19.2.8(react@19.2.8))(react@19.2.8)': + '@floating-ui/react-dom@2.1.9(react-dom@19.2.8(react@19.2.8))(react@19.2.8)': dependencies: '@floating-ui/dom': 1.8.0 react: 19.2.8 react-dom: 19.2.8(react@19.2.8) - '@floating-ui/react@0.27.19(react-dom@19.2.8(react@19.2.8))(react@19.2.8)': + '@floating-ui/react@0.27.20(react-dom@19.2.8(react@19.2.8))(react@19.2.8)': dependencies: - '@floating-ui/react-dom': 2.1.8(react-dom@19.2.8(react@19.2.8))(react@19.2.8) + '@floating-ui/react-dom': 2.1.9(react-dom@19.2.8(react@19.2.8))(react@19.2.8) '@floating-ui/utils': 0.2.12 react: 19.2.8 react-dom: 19.2.8(react@19.2.8) - tabbable: 6.4.0 + tabbable: 6.5.0 '@floating-ui/utils@0.2.12': {} @@ -4108,13 +4132,13 @@ snapshots: jest-util: 30.4.1 slash: 3.0.0 - '@jest/core@30.4.2': + '@jest/core@30.4.2(supports-color@8.1.1)': dependencies: '@jest/console': 30.4.1 '@jest/pattern': 30.4.0 - '@jest/reporters': 30.4.1 + '@jest/reporters': 30.4.1(supports-color@8.1.1) '@jest/test-result': 30.4.1 - '@jest/transform': 30.4.1 + '@jest/transform': 30.4.1(supports-color@8.1.1) '@jest/types': 30.4.1 '@types/node': 26.0.1 ansi-escapes: 4.3.2 @@ -4124,15 +4148,15 @@ snapshots: fast-json-stable-stringify: 2.1.0 graceful-fs: 4.2.11 jest-changed-files: 30.4.1 - jest-config: 30.4.2(@types/node@26.0.1) + jest-config: 30.4.2(@types/node@26.0.1)(supports-color@8.1.1) jest-haste-map: 30.4.1 jest-message-util: 30.4.1 jest-regex-util: 30.4.0 jest-resolve: 30.4.1 - jest-resolve-dependencies: 30.4.2 - jest-runner: 30.4.2 - jest-runtime: 30.4.2 - jest-snapshot: 30.4.1 + jest-resolve-dependencies: 30.4.2(supports-color@8.1.1) + jest-runner: 30.4.2(supports-color@8.1.1) + jest-runtime: 30.4.2(supports-color@8.1.1) + jest-snapshot: 30.4.1(supports-color@8.1.1) jest-util: 30.4.1 jest-validate: 30.4.1 jest-watcher: 30.4.1 @@ -4161,10 +4185,10 @@ snapshots: dependencies: '@jest/get-type': 30.1.0 - '@jest/expect@30.4.1': + '@jest/expect@30.4.1(supports-color@8.1.1)': dependencies: expect: 30.4.1 - jest-snapshot: 30.4.1 + jest-snapshot: 30.4.1(supports-color@8.1.1) transitivePeerDependencies: - supports-color @@ -4179,10 +4203,10 @@ snapshots: '@jest/get-type@30.1.0': {} - '@jest/globals@30.4.1': + '@jest/globals@30.4.1(supports-color@8.1.1)': dependencies: '@jest/environment': 30.4.1 - '@jest/expect': 30.4.1 + '@jest/expect': 30.4.1(supports-color@8.1.1) '@jest/types': 30.4.1 jest-mock: 30.4.1 transitivePeerDependencies: @@ -4193,12 +4217,12 @@ snapshots: '@types/node': 26.0.1 jest-regex-util: 30.4.0 - '@jest/reporters@30.4.1': + '@jest/reporters@30.4.1(supports-color@8.1.1)': dependencies: '@bcoe/v8-coverage': 0.2.3 '@jest/console': 30.4.1 '@jest/test-result': 30.4.1 - '@jest/transform': 30.4.1 + '@jest/transform': 30.4.1(supports-color@8.1.1) '@jest/types': 30.4.1 '@jridgewell/trace-mapping': 0.3.31 '@types/node': 26.0.1 @@ -4208,9 +4232,9 @@ snapshots: glob: 10.5.0 graceful-fs: 4.2.11 istanbul-lib-coverage: 3.2.2 - istanbul-lib-instrument: 6.0.3 + istanbul-lib-instrument: 6.0.3(supports-color@8.1.1) istanbul-lib-report: 3.0.1 - istanbul-lib-source-maps: 5.0.6 + istanbul-lib-source-maps: 5.0.6(supports-color@8.1.1) istanbul-reports: 3.2.0 jest-message-util: 30.4.1 jest-util: 30.4.1 @@ -4256,12 +4280,12 @@ snapshots: jest-haste-map: 30.4.1 slash: 3.0.0 - '@jest/transform@30.4.1': + '@jest/transform@30.4.1(supports-color@8.1.1)': dependencies: - '@babel/core': 7.29.7 + '@babel/core': 7.29.7(supports-color@8.1.1) '@jest/types': 30.4.1 '@jridgewell/trace-mapping': 0.3.31 - babel-plugin-istanbul: 7.0.1 + babel-plugin-istanbul: 7.0.1(supports-color@8.1.1) chalk: 4.1.2 convert-source-map: 2.0.0 fast-json-stable-stringify: 2.1.0 @@ -4328,50 +4352,50 @@ snapshots: dependencies: '@lezer/common': 1.5.2 - '@mantine/code-highlight@9.5.0(@mantine/core@9.5.0(@mantine/hooks@9.5.0(react@19.2.8))(@types/react@19.2.17)(react-dom@19.2.8(react@19.2.8))(react@19.2.8))(@mantine/hooks@9.5.0(react@19.2.8))(react-dom@19.2.8(react@19.2.8))(react@19.2.8)': + '@mantine/code-highlight@9.5.1(@mantine/core@9.5.1(@mantine/hooks@9.5.1(react@19.2.8))(@types/react@19.2.18)(react-dom@19.2.8(react@19.2.8))(react@19.2.8))(@mantine/hooks@9.5.1(react@19.2.8))(react-dom@19.2.8(react@19.2.8))(react@19.2.8)': dependencies: - '@mantine/core': 9.5.0(@mantine/hooks@9.5.0(react@19.2.8))(@types/react@19.2.17)(react-dom@19.2.8(react@19.2.8))(react@19.2.8) - '@mantine/hooks': 9.5.0(react@19.2.8) + '@mantine/core': 9.5.1(@mantine/hooks@9.5.1(react@19.2.8))(@types/react@19.2.18)(react-dom@19.2.8(react@19.2.8))(react@19.2.8) + '@mantine/hooks': 9.5.1(react@19.2.8) clsx: 2.1.1 react: 19.2.8 react-dom: 19.2.8(react@19.2.8) - '@mantine/core@9.5.0(@mantine/hooks@9.5.0(react@19.2.8))(@types/react@19.2.17)(react-dom@19.2.8(react@19.2.8))(react@19.2.8)': + '@mantine/core@9.5.1(@mantine/hooks@9.5.1(react@19.2.8))(@types/react@19.2.18)(react-dom@19.2.8(react@19.2.8))(react@19.2.8)': dependencies: - '@floating-ui/react': 0.27.19(react-dom@19.2.8(react@19.2.8))(react@19.2.8) - '@mantine/hooks': 9.5.0(react@19.2.8) + '@floating-ui/react': 0.27.20(react-dom@19.2.8(react@19.2.8))(react@19.2.8) + '@mantine/hooks': 9.5.1(react@19.2.8) clsx: 2.1.1 react: 19.2.8 react-dom: 19.2.8(react@19.2.8) react-number-format: 5.4.5(react-dom@19.2.8(react@19.2.8))(react@19.2.8) - react-remove-scroll: 2.7.2(@types/react@19.2.17)(react@19.2.8) + react-remove-scroll: 2.7.2(@types/react@19.2.18)(react@19.2.8) type-fest: 5.8.0 transitivePeerDependencies: - '@types/react' - '@mantine/dates@9.5.0(@mantine/core@9.5.0(@mantine/hooks@9.5.0(react@19.2.8))(@types/react@19.2.17)(react-dom@19.2.8(react@19.2.8))(react@19.2.8))(@mantine/hooks@9.5.0(react@19.2.8))(dayjs@1.11.21)(react-dom@19.2.8(react@19.2.8))(react@19.2.8)': + '@mantine/dates@9.5.1(@mantine/core@9.5.1(@mantine/hooks@9.5.1(react@19.2.8))(@types/react@19.2.18)(react-dom@19.2.8(react@19.2.8))(react@19.2.8))(@mantine/hooks@9.5.1(react@19.2.8))(dayjs@1.11.21)(react-dom@19.2.8(react@19.2.8))(react@19.2.8)': dependencies: - '@mantine/core': 9.5.0(@mantine/hooks@9.5.0(react@19.2.8))(@types/react@19.2.17)(react-dom@19.2.8(react@19.2.8))(react@19.2.8) - '@mantine/hooks': 9.5.0(react@19.2.8) + '@mantine/core': 9.5.1(@mantine/hooks@9.5.1(react@19.2.8))(@types/react@19.2.18)(react-dom@19.2.8(react@19.2.8))(react@19.2.8) + '@mantine/hooks': 9.5.1(react@19.2.8) clsx: 2.1.1 dayjs: 1.11.21 react: 19.2.8 react-dom: 19.2.8(react@19.2.8) - '@mantine/hooks@9.5.0(react@19.2.8)': + '@mantine/hooks@9.5.1(react@19.2.8)': dependencies: react: 19.2.8 - '@mantine/notifications@9.5.0(@mantine/core@9.5.0(@mantine/hooks@9.5.0(react@19.2.8))(@types/react@19.2.17)(react-dom@19.2.8(react@19.2.8))(react@19.2.8))(@mantine/hooks@9.5.0(react@19.2.8))(react-dom@19.2.8(react@19.2.8))(react@19.2.8)': + '@mantine/notifications@9.5.1(@mantine/core@9.5.1(@mantine/hooks@9.5.1(react@19.2.8))(@types/react@19.2.18)(react-dom@19.2.8(react@19.2.8))(react@19.2.8))(@mantine/hooks@9.5.1(react@19.2.8))(react-dom@19.2.8(react@19.2.8))(react@19.2.8)': dependencies: - '@mantine/core': 9.5.0(@mantine/hooks@9.5.0(react@19.2.8))(@types/react@19.2.17)(react-dom@19.2.8(react@19.2.8))(react@19.2.8) - '@mantine/hooks': 9.5.0(react@19.2.8) - '@mantine/store': 9.5.0(react@19.2.8) + '@mantine/core': 9.5.1(@mantine/hooks@9.5.1(react@19.2.8))(@types/react@19.2.18)(react-dom@19.2.8(react@19.2.8))(react@19.2.8) + '@mantine/hooks': 9.5.1(react@19.2.8) + '@mantine/store': 9.5.1(react@19.2.8) react: 19.2.8 react-dom: 19.2.8(react@19.2.8) react-transition-group: 4.4.5(react-dom@19.2.8(react@19.2.8))(react@19.2.8) - '@mantine/store@9.5.0(react@19.2.8)': + '@mantine/store@9.5.1(react@19.2.8)': dependencies: react: 19.2.8 @@ -4388,6 +4412,9 @@ snapshots: outvariant: 1.4.3 strict-event-emitter: 0.5.1 + '@napi-rs/lzma-linux-x64-gnu@1.5.1': + optional: true + '@napi-rs/wasm-runtime@1.1.6(@emnapi/core@1.10.0)(@emnapi/runtime@1.10.0)': dependencies: '@emnapi/core': 1.10.0 @@ -4415,7 +4442,7 @@ snapshots: '@pkgr/core@0.3.6': {} - '@reduxjs/toolkit@2.12.0(react-redux@9.3.0(@types/react@19.2.17)(react@19.2.8)(redux@5.0.1))(react@19.2.8)': + '@reduxjs/toolkit@2.12.0(react-redux@9.3.0(@types/react@19.2.18)(react@19.2.8)(redux@5.0.1))(react@19.2.8)': dependencies: '@standard-schema/spec': 1.1.0 '@standard-schema/utils': 0.3.0 @@ -4425,101 +4452,101 @@ snapshots: reselect: 5.2.0 optionalDependencies: react: 19.2.8 - react-redux: 9.3.0(@types/react@19.2.17)(react@19.2.8)(redux@5.0.1) + react-redux: 9.3.0(@types/react@19.2.18)(react@19.2.8)(redux@5.0.1) '@rolldown/pluginutils@1.0.0-beta.27': {} - '@rollup/plugin-node-resolve@16.0.3(rollup@4.62.3)': + '@rollup/plugin-node-resolve@16.0.3(rollup@4.62.4)': dependencies: - '@rollup/pluginutils': 5.3.0(rollup@4.62.3) + '@rollup/pluginutils': 5.3.0(rollup@4.62.4) '@types/resolve': 1.20.2 deepmerge: 4.3.1 is-module: 1.0.0 resolve: 1.22.12 optionalDependencies: - rollup: 4.62.3 + rollup: 4.62.4 - '@rollup/pluginutils@5.3.0(rollup@4.62.3)': + '@rollup/pluginutils@5.3.0(rollup@4.62.4)': dependencies: '@types/estree': 1.0.9 estree-walker: 2.0.2 picomatch: 4.0.4 optionalDependencies: - rollup: 4.62.3 + rollup: 4.62.4 - '@rollup/rollup-android-arm-eabi@4.62.3': + '@rollup/rollup-android-arm-eabi@4.62.4': optional: true - '@rollup/rollup-android-arm64@4.62.3': + '@rollup/rollup-android-arm64@4.62.4': optional: true - '@rollup/rollup-darwin-arm64@4.62.3': + '@rollup/rollup-darwin-arm64@4.62.4': optional: true - '@rollup/rollup-darwin-x64@4.62.3': + '@rollup/rollup-darwin-x64@4.62.4': optional: true - '@rollup/rollup-freebsd-arm64@4.62.3': + '@rollup/rollup-freebsd-arm64@4.62.4': optional: true - '@rollup/rollup-freebsd-x64@4.62.3': + '@rollup/rollup-freebsd-x64@4.62.4': optional: true - '@rollup/rollup-linux-arm-gnueabihf@4.62.3': + '@rollup/rollup-linux-arm-gnueabihf@4.62.4': optional: true - '@rollup/rollup-linux-arm-musleabihf@4.62.3': + '@rollup/rollup-linux-arm-musleabihf@4.62.4': optional: true - '@rollup/rollup-linux-arm64-gnu@4.62.3': + '@rollup/rollup-linux-arm64-gnu@4.62.4': optional: true - '@rollup/rollup-linux-arm64-musl@4.62.3': + '@rollup/rollup-linux-arm64-musl@4.62.4': optional: true - '@rollup/rollup-linux-loong64-gnu@4.62.3': + '@rollup/rollup-linux-loong64-gnu@4.62.4': optional: true - '@rollup/rollup-linux-loong64-musl@4.62.3': + '@rollup/rollup-linux-loong64-musl@4.62.4': optional: true - '@rollup/rollup-linux-ppc64-gnu@4.62.3': + '@rollup/rollup-linux-ppc64-gnu@4.62.4': optional: true - '@rollup/rollup-linux-ppc64-musl@4.62.3': + '@rollup/rollup-linux-ppc64-musl@4.62.4': optional: true - '@rollup/rollup-linux-riscv64-gnu@4.62.3': + '@rollup/rollup-linux-riscv64-gnu@4.62.4': optional: true - '@rollup/rollup-linux-riscv64-musl@4.62.3': + '@rollup/rollup-linux-riscv64-musl@4.62.4': optional: true - '@rollup/rollup-linux-s390x-gnu@4.62.3': + '@rollup/rollup-linux-s390x-gnu@4.62.4': optional: true - '@rollup/rollup-linux-x64-gnu@4.62.3': + '@rollup/rollup-linux-x64-gnu@4.62.4': optional: true - '@rollup/rollup-linux-x64-musl@4.62.3': + '@rollup/rollup-linux-x64-musl@4.62.4': optional: true - '@rollup/rollup-openbsd-x64@4.62.3': + '@rollup/rollup-openbsd-x64@4.62.4': optional: true - '@rollup/rollup-openharmony-arm64@4.62.3': + '@rollup/rollup-openharmony-arm64@4.62.4': optional: true - '@rollup/rollup-win32-arm64-msvc@4.62.3': + '@rollup/rollup-win32-arm64-msvc@4.62.4': optional: true - '@rollup/rollup-win32-ia32-msvc@4.62.3': + '@rollup/rollup-win32-ia32-msvc@4.62.4': optional: true - '@rollup/rollup-win32-x64-gnu@4.62.3': + '@rollup/rollup-win32-x64-gnu@4.62.4': optional: true - '@rollup/rollup-win32-x64-msvc@4.62.3': + '@rollup/rollup-win32-x64-msvc@4.62.4': optional: true '@sinclair/typebox@0.27.10': {} @@ -4538,12 +4565,12 @@ snapshots: '@standard-schema/utils@0.3.0': {} - '@tabler/icons-react@3.45.0(react@19.2.8)': + '@tabler/icons-react@3.46.0(react@19.2.8)': dependencies: - '@tabler/icons': 3.45.0 + '@tabler/icons': 3.46.0 react: 19.2.8 - '@tabler/icons@3.45.0': {} + '@tabler/icons@3.46.0': {} '@tanstack/query-core@5.101.4': {} @@ -4573,15 +4600,15 @@ snapshots: picocolors: 1.1.1 redent: 3.0.0 - '@testing-library/react@16.3.2(@testing-library/dom@10.4.1)(@types/react-dom@19.2.3(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.8(react@19.2.8))(react@19.2.8)': + '@testing-library/react@16.3.2(@testing-library/dom@10.4.1)(@types/react-dom@19.2.4(@types/react@19.2.18))(@types/react@19.2.18)(react-dom@19.2.8(react@19.2.8))(react@19.2.8)': dependencies: '@babel/runtime': 7.29.7 '@testing-library/dom': 10.4.1 react: 19.2.8 react-dom: 19.2.8(react@19.2.8) optionalDependencies: - '@types/react': 19.2.17 - '@types/react-dom': 19.2.3(@types/react@19.2.17) + '@types/react': 19.2.18 + '@types/react-dom': 19.2.4(@types/react@19.2.18) '@tybys/wasm-util@0.10.3': dependencies: @@ -4637,17 +4664,17 @@ snapshots: '@types/json-schema@7.0.15': {} - '@types/lodash@4.17.24': {} + '@types/lodash@4.17.25': {} '@types/node@26.0.1': dependencies: undici-types: 8.3.0 - '@types/react-dom@19.2.3(@types/react@19.2.17)': + '@types/react-dom@19.2.4(@types/react@19.2.18)': dependencies: - '@types/react': 19.2.17 + '@types/react': 19.2.18 - '@types/react@19.2.17': + '@types/react@19.2.18': dependencies: csstype: 3.2.3 @@ -4667,74 +4694,74 @@ snapshots: dependencies: '@types/yargs-parser': 21.0.3 - '@typescript-eslint/eslint-plugin@8.65.0(@typescript-eslint/parser@8.65.0(eslint@9.39.5)(typescript@5.9.3))(eslint@9.39.5)(typescript@5.9.3)': + '@typescript-eslint/eslint-plugin@8.66.0(@typescript-eslint/parser@8.66.0(eslint@9.39.5(supports-color@8.1.1))(supports-color@8.1.1)(typescript@5.9.3))(eslint@9.39.5(supports-color@8.1.1))(supports-color@8.1.1)(typescript@5.9.3)': dependencies: '@eslint-community/regexpp': 4.12.2 - '@typescript-eslint/parser': 8.65.0(eslint@9.39.5)(typescript@5.9.3) - '@typescript-eslint/scope-manager': 8.65.0 - '@typescript-eslint/type-utils': 8.65.0(eslint@9.39.5)(typescript@5.9.3) - '@typescript-eslint/utils': 8.65.0(eslint@9.39.5)(typescript@5.9.3) - '@typescript-eslint/visitor-keys': 8.65.0 - eslint: 9.39.5 - ignore: 7.0.5 + '@typescript-eslint/parser': 8.66.0(eslint@9.39.5(supports-color@8.1.1))(supports-color@8.1.1)(typescript@5.9.3) + '@typescript-eslint/scope-manager': 8.66.0 + '@typescript-eslint/type-utils': 8.66.0(eslint@9.39.5(supports-color@8.1.1))(supports-color@8.1.1)(typescript@5.9.3) + '@typescript-eslint/utils': 8.66.0(eslint@9.39.5(supports-color@8.1.1))(supports-color@8.1.1)(typescript@5.9.3) + '@typescript-eslint/visitor-keys': 8.66.0 + eslint: 9.39.5(supports-color@8.1.1) + ignore: 7.0.6 natural-compare: 1.4.0 ts-api-utils: 2.5.0(typescript@5.9.3) typescript: 5.9.3 transitivePeerDependencies: - supports-color - '@typescript-eslint/parser@8.65.0(eslint@9.39.5)(typescript@5.9.3)': + '@typescript-eslint/parser@8.66.0(eslint@9.39.5(supports-color@8.1.1))(supports-color@8.1.1)(typescript@5.9.3)': dependencies: - '@typescript-eslint/scope-manager': 8.65.0 - '@typescript-eslint/types': 8.65.0 - '@typescript-eslint/typescript-estree': 8.65.0(typescript@5.9.3) - '@typescript-eslint/visitor-keys': 8.65.0 - debug: 4.4.3 - eslint: 9.39.5 + '@typescript-eslint/scope-manager': 8.66.0 + '@typescript-eslint/types': 8.66.0 + '@typescript-eslint/typescript-estree': 8.66.0(supports-color@8.1.1)(typescript@5.9.3) + '@typescript-eslint/visitor-keys': 8.66.0 + debug: 4.4.3(supports-color@8.1.1) + eslint: 9.39.5(supports-color@8.1.1) typescript: 5.9.3 transitivePeerDependencies: - supports-color - '@typescript-eslint/project-service@8.65.0(typescript@5.9.3)': + '@typescript-eslint/project-service@8.66.0(supports-color@8.1.1)(typescript@5.9.3)': dependencies: - '@typescript-eslint/tsconfig-utils': 8.65.0(typescript@5.9.3) - '@typescript-eslint/types': 8.65.0 - debug: 4.4.3 + '@typescript-eslint/tsconfig-utils': 8.66.0(typescript@5.9.3) + '@typescript-eslint/types': 8.66.0 + debug: 4.4.3(supports-color@8.1.1) typescript: 5.9.3 transitivePeerDependencies: - supports-color - '@typescript-eslint/scope-manager@8.65.0': + '@typescript-eslint/scope-manager@8.66.0': dependencies: - '@typescript-eslint/types': 8.65.0 - '@typescript-eslint/visitor-keys': 8.65.0 + '@typescript-eslint/types': 8.66.0 + '@typescript-eslint/visitor-keys': 8.66.0 - '@typescript-eslint/tsconfig-utils@8.65.0(typescript@5.9.3)': + '@typescript-eslint/tsconfig-utils@8.66.0(typescript@5.9.3)': dependencies: typescript: 5.9.3 - '@typescript-eslint/type-utils@8.65.0(eslint@9.39.5)(typescript@5.9.3)': + '@typescript-eslint/type-utils@8.66.0(eslint@9.39.5(supports-color@8.1.1))(supports-color@8.1.1)(typescript@5.9.3)': dependencies: - '@typescript-eslint/types': 8.65.0 - '@typescript-eslint/typescript-estree': 8.65.0(typescript@5.9.3) - '@typescript-eslint/utils': 8.65.0(eslint@9.39.5)(typescript@5.9.3) - debug: 4.4.3 - eslint: 9.39.5 + '@typescript-eslint/types': 8.66.0 + '@typescript-eslint/typescript-estree': 8.66.0(supports-color@8.1.1)(typescript@5.9.3) + '@typescript-eslint/utils': 8.66.0(eslint@9.39.5(supports-color@8.1.1))(supports-color@8.1.1)(typescript@5.9.3) + debug: 4.4.3(supports-color@8.1.1) + eslint: 9.39.5(supports-color@8.1.1) ts-api-utils: 2.5.0(typescript@5.9.3) typescript: 5.9.3 transitivePeerDependencies: - supports-color - '@typescript-eslint/types@8.65.0': {} + '@typescript-eslint/types@8.66.0': {} - '@typescript-eslint/typescript-estree@8.65.0(typescript@5.9.3)': + '@typescript-eslint/typescript-estree@8.66.0(supports-color@8.1.1)(typescript@5.9.3)': dependencies: - '@typescript-eslint/project-service': 8.65.0(typescript@5.9.3) - '@typescript-eslint/tsconfig-utils': 8.65.0(typescript@5.9.3) - '@typescript-eslint/types': 8.65.0 - '@typescript-eslint/visitor-keys': 8.65.0 - debug: 4.4.3 - minimatch: 10.2.5 + '@typescript-eslint/project-service': 8.66.0(supports-color@8.1.1)(typescript@5.9.3) + '@typescript-eslint/tsconfig-utils': 8.66.0(typescript@5.9.3) + '@typescript-eslint/types': 8.66.0 + '@typescript-eslint/visitor-keys': 8.66.0 + debug: 4.4.3(supports-color@8.1.1) + minimatch: 10.2.6 semver: 7.8.5 tinyglobby: 0.2.17 ts-api-utils: 2.5.0(typescript@5.9.3) @@ -4742,23 +4769,23 @@ snapshots: transitivePeerDependencies: - supports-color - '@typescript-eslint/utils@8.65.0(eslint@9.39.5)(typescript@5.9.3)': + '@typescript-eslint/utils@8.66.0(eslint@9.39.5(supports-color@8.1.1))(supports-color@8.1.1)(typescript@5.9.3)': dependencies: - '@eslint-community/eslint-utils': 4.9.1(eslint@9.39.5) - '@typescript-eslint/scope-manager': 8.65.0 - '@typescript-eslint/types': 8.65.0 - '@typescript-eslint/typescript-estree': 8.65.0(typescript@5.9.3) - eslint: 9.39.5 + '@eslint-community/eslint-utils': 4.10.1(eslint@9.39.5(supports-color@8.1.1)) + '@typescript-eslint/scope-manager': 8.66.0 + '@typescript-eslint/types': 8.66.0 + '@typescript-eslint/typescript-estree': 8.66.0(supports-color@8.1.1)(typescript@5.9.3) + eslint: 9.39.5(supports-color@8.1.1) typescript: 5.9.3 transitivePeerDependencies: - supports-color - '@typescript-eslint/visitor-keys@8.65.0': + '@typescript-eslint/visitor-keys@8.66.0': dependencies: - '@typescript-eslint/types': 8.65.0 + '@typescript-eslint/types': 8.66.0 eslint-visitor-keys: 5.0.1 - '@uiw/codemirror-extensions-basic-setup@4.25.11(@codemirror/autocomplete@6.20.3)(@codemirror/commands@6.10.4)(@codemirror/language@6.12.4)(@codemirror/lint@6.9.7)(@codemirror/search@6.7.1)(@codemirror/state@6.7.1)(@codemirror/view@6.43.6)': + '@uiw/codemirror-extensions-basic-setup@4.25.11(@codemirror/autocomplete@6.20.3)(@codemirror/commands@6.10.4)(@codemirror/language@6.12.4)(@codemirror/lint@6.9.7)(@codemirror/search@6.7.1)(@codemirror/state@6.7.1)(@codemirror/view@6.43.8)': dependencies: '@codemirror/autocomplete': 6.20.3 '@codemirror/commands': 6.10.4 @@ -4766,16 +4793,16 @@ snapshots: '@codemirror/lint': 6.9.7 '@codemirror/search': 6.7.1 '@codemirror/state': 6.7.1 - '@codemirror/view': 6.43.6 + '@codemirror/view': 6.43.8 - '@uiw/react-codemirror@4.25.11(@babel/runtime@7.29.7)(@codemirror/autocomplete@6.20.3)(@codemirror/language@6.12.4)(@codemirror/lint@6.9.7)(@codemirror/search@6.7.1)(@codemirror/state@6.7.1)(@codemirror/theme-one-dark@6.1.3)(@codemirror/view@6.43.6)(codemirror@6.0.2)(react-dom@19.2.8(react@19.2.8))(react@19.2.8)': + '@uiw/react-codemirror@4.25.11(@babel/runtime@7.29.7)(@codemirror/autocomplete@6.20.3)(@codemirror/language@6.12.4)(@codemirror/lint@6.9.7)(@codemirror/search@6.7.1)(@codemirror/state@6.7.1)(@codemirror/theme-one-dark@6.1.3)(@codemirror/view@6.43.8)(codemirror@6.0.2)(react-dom@19.2.8(react@19.2.8))(react@19.2.8)': dependencies: '@babel/runtime': 7.29.7 '@codemirror/commands': 6.10.4 '@codemirror/state': 6.7.1 '@codemirror/theme-one-dark': 6.1.3 - '@codemirror/view': 6.43.6 - '@uiw/codemirror-extensions-basic-setup': 4.25.11(@codemirror/autocomplete@6.20.3)(@codemirror/commands@6.10.4)(@codemirror/language@6.12.4)(@codemirror/lint@6.9.7)(@codemirror/search@6.7.1)(@codemirror/state@6.7.1)(@codemirror/view@6.43.6) + '@codemirror/view': 6.43.8 + '@uiw/codemirror-extensions-basic-setup': 4.25.11(@codemirror/autocomplete@6.20.3)(@codemirror/commands@6.10.4)(@codemirror/language@6.12.4)(@codemirror/lint@6.9.7)(@codemirror/search@6.7.1)(@codemirror/state@6.7.1)(@codemirror/view@6.43.8) codemirror: 6.0.2 react: 19.2.8 react-dom: 19.2.8(react@19.2.8) @@ -4857,15 +4884,15 @@ snapshots: '@unrs/resolver-binding-win32-x64-msvc@1.12.2': optional: true - '@vitejs/plugin-react@4.7.0(vite@6.4.3(@types/node@26.0.1)(sugarss@5.0.1(postcss@8.5.23)))': + '@vitejs/plugin-react@4.7.0(supports-color@8.1.1)(vite@6.4.3(@types/node@26.0.1)(sugarss@5.0.1(postcss@8.5.26)))': dependencies: - '@babel/core': 7.29.7 - '@babel/plugin-transform-react-jsx-self': 7.29.7(@babel/core@7.29.7) - '@babel/plugin-transform-react-jsx-source': 7.29.7(@babel/core@7.29.7) + '@babel/core': 7.29.7(supports-color@8.1.1) + '@babel/plugin-transform-react-jsx-self': 7.29.7(@babel/core@7.29.7(supports-color@8.1.1)) + '@babel/plugin-transform-react-jsx-source': 7.29.7(@babel/core@7.29.7(supports-color@8.1.1)) '@rolldown/pluginutils': 1.0.0-beta.27 '@types/babel__core': 7.20.5 react-refresh: 0.17.0 - vite: 6.4.3(@types/node@26.0.1)(sugarss@5.0.1(postcss@8.5.23)) + vite: 6.4.3(@types/node@26.0.1)(sugarss@5.0.1(postcss@8.5.26)) transitivePeerDependencies: - supports-color @@ -4877,13 +4904,13 @@ snapshots: chai: 5.3.3 tinyrainbow: 2.0.0 - '@vitest/mocker@3.2.7(vite@6.4.3(@types/node@26.0.1)(sugarss@5.0.1(postcss@8.5.23)))': + '@vitest/mocker@3.2.7(vite@6.4.3(@types/node@26.0.1)(sugarss@5.0.1(postcss@8.5.26)))': dependencies: '@vitest/spy': 3.2.7 estree-walker: 3.0.3 magic-string: 0.30.21 optionalDependencies: - vite: 6.4.3(@types/node@26.0.1)(sugarss@5.0.1(postcss@8.5.23)) + vite: 6.4.3(@types/node@26.0.1)(sugarss@5.0.1(postcss@8.5.26)) '@vitest/pretty-format@3.2.7': dependencies: @@ -4965,25 +4992,25 @@ snapshots: asynckit@0.4.0: {} - babel-jest@30.4.1(@babel/core@7.29.7): + babel-jest@30.4.1(@babel/core@7.29.7(supports-color@8.1.1))(supports-color@8.1.1): dependencies: - '@babel/core': 7.29.7 - '@jest/transform': 30.4.1 + '@babel/core': 7.29.7(supports-color@8.1.1) + '@jest/transform': 30.4.1(supports-color@8.1.1) '@types/babel__core': 7.20.5 - babel-plugin-istanbul: 7.0.1 - babel-preset-jest: 30.4.0(@babel/core@7.29.7) + babel-plugin-istanbul: 7.0.1(supports-color@8.1.1) + babel-preset-jest: 30.4.0(@babel/core@7.29.7(supports-color@8.1.1)) chalk: 4.1.2 graceful-fs: 4.2.11 slash: 3.0.0 transitivePeerDependencies: - supports-color - babel-plugin-istanbul@7.0.1: + babel-plugin-istanbul@7.0.1(supports-color@8.1.1): dependencies: '@babel/helper-plugin-utils': 7.29.7 '@istanbuljs/load-nyc-config': 1.1.0 '@istanbuljs/schema': 0.1.6 - istanbul-lib-instrument: 6.0.3 + istanbul-lib-instrument: 6.0.3(supports-color@8.1.1) test-exclude: 6.0.0 transitivePeerDependencies: - supports-color @@ -4992,30 +5019,30 @@ snapshots: dependencies: '@types/babel__core': 7.20.5 - babel-preset-current-node-syntax@1.2.0(@babel/core@7.29.7): - dependencies: - '@babel/core': 7.29.7 - '@babel/plugin-syntax-async-generators': 7.8.4(@babel/core@7.29.7) - '@babel/plugin-syntax-bigint': 7.8.3(@babel/core@7.29.7) - '@babel/plugin-syntax-class-properties': 7.12.13(@babel/core@7.29.7) - '@babel/plugin-syntax-class-static-block': 7.14.5(@babel/core@7.29.7) - '@babel/plugin-syntax-import-attributes': 7.29.7(@babel/core@7.29.7) - '@babel/plugin-syntax-import-meta': 7.10.4(@babel/core@7.29.7) - '@babel/plugin-syntax-json-strings': 7.8.3(@babel/core@7.29.7) - '@babel/plugin-syntax-logical-assignment-operators': 7.10.4(@babel/core@7.29.7) - '@babel/plugin-syntax-nullish-coalescing-operator': 7.8.3(@babel/core@7.29.7) - '@babel/plugin-syntax-numeric-separator': 7.10.4(@babel/core@7.29.7) - '@babel/plugin-syntax-object-rest-spread': 7.8.3(@babel/core@7.29.7) - '@babel/plugin-syntax-optional-catch-binding': 7.8.3(@babel/core@7.29.7) - '@babel/plugin-syntax-optional-chaining': 7.8.3(@babel/core@7.29.7) - '@babel/plugin-syntax-private-property-in-object': 7.14.5(@babel/core@7.29.7) - '@babel/plugin-syntax-top-level-await': 7.14.5(@babel/core@7.29.7) - - babel-preset-jest@30.4.0(@babel/core@7.29.7): - dependencies: - '@babel/core': 7.29.7 + babel-preset-current-node-syntax@1.2.0(@babel/core@7.29.7(supports-color@8.1.1)): + dependencies: + '@babel/core': 7.29.7(supports-color@8.1.1) + '@babel/plugin-syntax-async-generators': 7.8.4(@babel/core@7.29.7(supports-color@8.1.1)) + '@babel/plugin-syntax-bigint': 7.8.3(@babel/core@7.29.7(supports-color@8.1.1)) + '@babel/plugin-syntax-class-properties': 7.12.13(@babel/core@7.29.7(supports-color@8.1.1)) + '@babel/plugin-syntax-class-static-block': 7.14.5(@babel/core@7.29.7(supports-color@8.1.1)) + '@babel/plugin-syntax-import-attributes': 7.29.7(@babel/core@7.29.7(supports-color@8.1.1)) + '@babel/plugin-syntax-import-meta': 7.10.4(@babel/core@7.29.7(supports-color@8.1.1)) + '@babel/plugin-syntax-json-strings': 7.8.3(@babel/core@7.29.7(supports-color@8.1.1)) + '@babel/plugin-syntax-logical-assignment-operators': 7.10.4(@babel/core@7.29.7(supports-color@8.1.1)) + '@babel/plugin-syntax-nullish-coalescing-operator': 7.8.3(@babel/core@7.29.7(supports-color@8.1.1)) + '@babel/plugin-syntax-numeric-separator': 7.10.4(@babel/core@7.29.7(supports-color@8.1.1)) + '@babel/plugin-syntax-object-rest-spread': 7.8.3(@babel/core@7.29.7(supports-color@8.1.1)) + '@babel/plugin-syntax-optional-catch-binding': 7.8.3(@babel/core@7.29.7(supports-color@8.1.1)) + '@babel/plugin-syntax-optional-chaining': 7.8.3(@babel/core@7.29.7(supports-color@8.1.1)) + '@babel/plugin-syntax-private-property-in-object': 7.14.5(@babel/core@7.29.7(supports-color@8.1.1)) + '@babel/plugin-syntax-top-level-await': 7.14.5(@babel/core@7.29.7(supports-color@8.1.1)) + + babel-preset-jest@30.4.0(@babel/core@7.29.7(supports-color@8.1.1)): + dependencies: + '@babel/core': 7.29.7(supports-color@8.1.1) babel-plugin-jest-hoist: 30.4.0 - babel-preset-current-node-syntax: 1.2.0(@babel/core@7.29.7) + babel-preset-current-node-syntax: 1.2.0(@babel/core@7.29.7(supports-color@8.1.1)) balanced-match@1.0.2: {} @@ -5032,7 +5059,7 @@ snapshots: dependencies: balanced-match: 1.0.2 - brace-expansion@5.0.6: + brace-expansion@5.0.9: dependencies: balanced-match: 4.0.4 @@ -5116,7 +5143,7 @@ snapshots: '@codemirror/lint': 6.9.7 '@codemirror/search': 6.7.1 '@codemirror/state': 6.7.1 - '@codemirror/view': 6.43.6 + '@codemirror/view': 6.43.8 collect-v8-coverage@1.0.3: {} @@ -5164,9 +5191,11 @@ snapshots: dayjs@1.11.21: {} - debug@4.4.3: + debug@4.4.3(supports-color@8.1.1): dependencies: ms: 2.1.3 + optionalDependencies: + supports-color: 8.1.1 decimal.js@10.6.0: {} @@ -5313,26 +5342,26 @@ snapshots: escape-string-regexp@4.0.0: {} - eslint-config-prettier@10.1.8(eslint@9.39.5): + eslint-config-prettier@10.1.8(eslint@9.39.5(supports-color@8.1.1)): dependencies: - eslint: 9.39.5 + eslint: 9.39.5(supports-color@8.1.1) - eslint-plugin-prettier@5.5.6(eslint-config-prettier@10.1.8(eslint@9.39.5))(eslint@9.39.5)(prettier@3.9.6): + eslint-plugin-prettier@5.5.6(eslint-config-prettier@10.1.8(eslint@9.39.5(supports-color@8.1.1)))(eslint@9.39.5(supports-color@8.1.1))(prettier@3.9.6): dependencies: - eslint: 9.39.5 + eslint: 9.39.5(supports-color@8.1.1) prettier: 3.9.6 prettier-linter-helpers: 1.0.1 synckit: 0.11.13 optionalDependencies: - eslint-config-prettier: 10.1.8(eslint@9.39.5) + eslint-config-prettier: 10.1.8(eslint@9.39.5(supports-color@8.1.1)) - eslint-plugin-react-hooks@5.2.0(eslint@9.39.5): + eslint-plugin-react-hooks@5.2.0(eslint@9.39.5(supports-color@8.1.1)): dependencies: - eslint: 9.39.5 + eslint: 9.39.5(supports-color@8.1.1) - eslint-plugin-react-refresh@0.5.3(eslint@9.39.5): + eslint-plugin-react-refresh@0.5.3(eslint@9.39.5(supports-color@8.1.1)): dependencies: - eslint: 9.39.5 + eslint: 9.39.5(supports-color@8.1.1) eslint-scope@8.4.0: dependencies: @@ -5345,14 +5374,14 @@ snapshots: eslint-visitor-keys@5.0.1: {} - eslint@9.39.5: + eslint@9.39.5(supports-color@8.1.1): dependencies: - '@eslint-community/eslint-utils': 4.9.1(eslint@9.39.5) + '@eslint-community/eslint-utils': 4.10.1(eslint@9.39.5(supports-color@8.1.1)) '@eslint-community/regexpp': 4.12.2 - '@eslint/config-array': 0.21.2 + '@eslint/config-array': 0.21.2(supports-color@8.1.1) '@eslint/config-helpers': 0.4.2 '@eslint/core': 0.17.0 - '@eslint/eslintrc': 3.3.6 + '@eslint/eslintrc': 3.3.6(supports-color@8.1.1) '@eslint/js': 9.39.5 '@eslint/plugin-kit': 0.4.1 '@humanfs/node': 0.16.8 @@ -5362,7 +5391,7 @@ snapshots: ajv: 6.15.0 chalk: 4.1.2 cross-spawn: 7.0.6 - debug: 4.4.3 + debug: 4.4.3(supports-color@8.1.1) escape-string-regexp: 4.0.0 eslint-scope: 8.4.0 eslint-visitor-keys: 4.2.1 @@ -5605,17 +5634,17 @@ snapshots: domutils: 4.0.2 entities: 8.0.0 - http-proxy-agent@7.0.2: + http-proxy-agent@7.0.2(supports-color@8.1.1): dependencies: agent-base: 7.1.4 - debug: 4.4.3 + debug: 4.4.3(supports-color@8.1.1) transitivePeerDependencies: - supports-color - https-proxy-agent@7.0.6: + https-proxy-agent@7.0.6(supports-color@8.1.1): dependencies: agent-base: 7.1.4 - debug: 4.4.3 + debug: 4.4.3(supports-color@8.1.1) transitivePeerDependencies: - supports-color @@ -5627,7 +5656,7 @@ snapshots: ignore@5.3.2: {} - ignore@7.0.5: {} + ignore@7.0.6: {} immer@11.1.8: {} @@ -5691,9 +5720,9 @@ snapshots: istanbul-lib-coverage@3.2.2: {} - istanbul-lib-instrument@6.0.3: + istanbul-lib-instrument@6.0.3(supports-color@8.1.1): dependencies: - '@babel/core': 7.29.7 + '@babel/core': 7.29.7(supports-color@8.1.1) '@babel/parser': 7.29.7 '@istanbuljs/schema': 0.1.6 istanbul-lib-coverage: 3.2.2 @@ -5707,10 +5736,10 @@ snapshots: make-dir: 4.0.0 supports-color: 7.2.0 - istanbul-lib-source-maps@5.0.6: + istanbul-lib-source-maps@5.0.6(supports-color@8.1.1): dependencies: '@jridgewell/trace-mapping': 0.3.31 - debug: 4.4.3 + debug: 4.4.3(supports-color@8.1.1) istanbul-lib-coverage: 3.2.2 transitivePeerDependencies: - supports-color @@ -5732,10 +5761,10 @@ snapshots: jest-util: 30.4.1 p-limit: 3.1.0 - jest-circus@30.4.2: + jest-circus@30.4.2(supports-color@8.1.1): dependencies: '@jest/environment': 30.4.1 - '@jest/expect': 30.4.1 + '@jest/expect': 30.4.1(supports-color@8.1.1) '@jest/test-result': 30.4.1 '@jest/types': 30.4.1 '@types/node': 26.0.1 @@ -5746,8 +5775,8 @@ snapshots: jest-each: 30.4.1 jest-matcher-utils: 30.4.1 jest-message-util: 30.4.1 - jest-runtime: 30.4.2 - jest-snapshot: 30.4.1 + jest-runtime: 30.4.2(supports-color@8.1.1) + jest-snapshot: 30.4.1(supports-color@8.1.1) jest-util: 30.4.1 p-limit: 3.1.0 pretty-format: 30.4.1 @@ -5758,15 +5787,15 @@ snapshots: - babel-plugin-macros - supports-color - jest-cli@30.4.2(@types/node@26.0.1): + jest-cli@30.4.2(@types/node@26.0.1)(supports-color@8.1.1): dependencies: - '@jest/core': 30.4.2 + '@jest/core': 30.4.2(supports-color@8.1.1) '@jest/test-result': 30.4.1 '@jest/types': 30.4.1 chalk: 4.1.2 exit-x: 0.2.2 import-local: 3.2.0 - jest-config: 30.4.2(@types/node@26.0.1) + jest-config: 30.4.2(@types/node@26.0.1)(supports-color@8.1.1) jest-util: 30.4.1 jest-validate: 30.4.1 yargs: 17.7.3 @@ -5777,25 +5806,25 @@ snapshots: - supports-color - ts-node - jest-config@30.4.2(@types/node@26.0.1): + jest-config@30.4.2(@types/node@26.0.1)(supports-color@8.1.1): dependencies: - '@babel/core': 7.29.7 + '@babel/core': 7.29.7(supports-color@8.1.1) '@jest/get-type': 30.1.0 '@jest/pattern': 30.4.0 '@jest/test-sequencer': 30.4.1 '@jest/types': 30.4.1 - babel-jest: 30.4.1(@babel/core@7.29.7) + babel-jest: 30.4.1(@babel/core@7.29.7(supports-color@8.1.1))(supports-color@8.1.1) chalk: 4.1.2 ci-info: 4.4.0 deepmerge: 4.3.1 glob: 10.5.0 graceful-fs: 4.2.11 - jest-circus: 30.4.2 + jest-circus: 30.4.2(supports-color@8.1.1) jest-docblock: 30.4.0 jest-environment-node: 30.4.1 jest-regex-util: 30.4.0 jest-resolve: 30.4.1 - jest-runner: 30.4.2 + jest-runner: 30.4.2(supports-color@8.1.1) jest-util: 30.4.1 jest-validate: 30.4.1 parse-json: 5.2.0 @@ -5917,10 +5946,10 @@ snapshots: jest-regex-util@30.4.0: {} - jest-resolve-dependencies@30.4.2: + jest-resolve-dependencies@30.4.2(supports-color@8.1.1): dependencies: jest-regex-util: 30.4.0 - jest-snapshot: 30.4.1 + jest-snapshot: 30.4.1(supports-color@8.1.1) transitivePeerDependencies: - supports-color @@ -5935,12 +5964,12 @@ snapshots: slash: 3.0.0 unrs-resolver: 1.12.2 - jest-runner@30.4.2: + jest-runner@30.4.2(supports-color@8.1.1): dependencies: '@jest/console': 30.4.1 '@jest/environment': 30.4.1 '@jest/test-result': 30.4.1 - '@jest/transform': 30.4.1 + '@jest/transform': 30.4.1(supports-color@8.1.1) '@jest/types': 30.4.1 '@types/node': 26.0.1 chalk: 4.1.2 @@ -5953,7 +5982,7 @@ snapshots: jest-leak-detector: 30.4.1 jest-message-util: 30.4.1 jest-resolve: 30.4.1 - jest-runtime: 30.4.2 + jest-runtime: 30.4.2(supports-color@8.1.1) jest-util: 30.4.1 jest-watcher: 30.4.1 jest-worker: 30.4.1 @@ -5962,14 +5991,14 @@ snapshots: transitivePeerDependencies: - supports-color - jest-runtime@30.4.2: + jest-runtime@30.4.2(supports-color@8.1.1): dependencies: '@jest/environment': 30.4.1 '@jest/fake-timers': 30.4.1 - '@jest/globals': 30.4.1 + '@jest/globals': 30.4.1(supports-color@8.1.1) '@jest/source-map': 30.0.1 '@jest/test-result': 30.4.1 - '@jest/transform': 30.4.1 + '@jest/transform': 30.4.1(supports-color@8.1.1) '@jest/types': 30.4.1 '@types/node': 26.0.1 chalk: 4.1.2 @@ -5982,26 +6011,26 @@ snapshots: jest-mock: 30.4.1 jest-regex-util: 30.4.0 jest-resolve: 30.4.1 - jest-snapshot: 30.4.1 + jest-snapshot: 30.4.1(supports-color@8.1.1) jest-util: 30.4.1 slash: 3.0.0 strip-bom: 4.0.0 transitivePeerDependencies: - supports-color - jest-snapshot@30.4.1: + jest-snapshot@30.4.1(supports-color@8.1.1): dependencies: - '@babel/core': 7.29.7 + '@babel/core': 7.29.7(supports-color@8.1.1) '@babel/generator': 7.29.7 - '@babel/plugin-syntax-jsx': 7.29.7(@babel/core@7.29.7) - '@babel/plugin-syntax-typescript': 7.29.7(@babel/core@7.29.7) + '@babel/plugin-syntax-jsx': 7.29.7(@babel/core@7.29.7(supports-color@8.1.1)) + '@babel/plugin-syntax-typescript': 7.29.7(@babel/core@7.29.7(supports-color@8.1.1)) '@babel/types': 7.29.7 '@jest/expect-utils': 30.4.1 '@jest/get-type': 30.1.0 '@jest/snapshot-utils': 30.4.1 - '@jest/transform': 30.4.1 + '@jest/transform': 30.4.1(supports-color@8.1.1) '@jest/types': 30.4.1 - babel-preset-current-node-syntax: 1.2.0(@babel/core@7.29.7) + babel-preset-current-node-syntax: 1.2.0(@babel/core@7.29.7(supports-color@8.1.1)) chalk: 4.1.2 expect: 30.4.1 graceful-fs: 4.2.11 @@ -6061,12 +6090,12 @@ snapshots: merge-stream: 2.0.0 supports-color: 8.1.1 - jest@30.4.2(@types/node@26.0.1): + jest@30.4.2(@types/node@26.0.1)(supports-color@8.1.1): dependencies: - '@jest/core': 30.4.2 + '@jest/core': 30.4.2(supports-color@8.1.1) '@jest/types': 30.4.1 import-local: 3.2.0 - jest-cli: 30.4.2(@types/node@26.0.1) + jest-cli: 30.4.2(@types/node@26.0.1)(supports-color@8.1.1) transitivePeerDependencies: - '@types/node' - babel-plugin-macros @@ -6087,15 +6116,15 @@ snapshots: dependencies: argparse: 2.0.1 - jsdom@25.0.1: + jsdom@25.0.1(supports-color@8.1.1): dependencies: cssstyle: 4.6.0 data-urls: 5.0.0 decimal.js: 10.6.0 form-data: 4.0.5 html-encoding-sniffer: 4.0.0 - http-proxy-agent: 7.0.2 - https-proxy-agent: 7.0.6 + http-proxy-agent: 7.0.2(supports-color@8.1.1) + https-proxy-agent: 7.0.6(supports-color@8.1.1) is-potential-custom-element-name: 1.0.1 nwsapi: 2.2.23 parse5: 7.3.0 @@ -6209,9 +6238,9 @@ snapshots: min-indent@1.0.1: {} - minimatch@10.2.5: + minimatch@10.2.6: dependencies: - brace-expansion: 5.0.6 + brace-expansion: 5.0.9 minimatch@3.1.5: dependencies: @@ -6231,13 +6260,15 @@ snapshots: nanoid@3.3.16: {} + nanoid@3.3.18: {} + napi-postinstall@0.3.4: {} natural-compare@1.4.0: {} neo-async@2.6.2: {} - nock@14.0.16: + nock@14.0.17: dependencies: '@mswjs/interceptors': 0.41.9 json-stringify-safe: 5.0.1 @@ -6348,38 +6379,38 @@ snapshots: dependencies: find-up: 4.1.0 - postcss-js@4.1.0(postcss@8.5.23): + postcss-js@4.1.0(postcss@8.5.26): dependencies: camelcase-css: 2.0.1 - postcss: 8.5.23 + postcss: 8.5.26 - postcss-mixins@12.1.2(postcss@8.5.23): + postcss-mixins@12.1.2(postcss@8.5.26): dependencies: - postcss: 8.5.23 - postcss-js: 4.1.0(postcss@8.5.23) - postcss-simple-vars: 7.0.1(postcss@8.5.23) - sugarss: 5.0.1(postcss@8.5.23) + postcss: 8.5.26 + postcss-js: 4.1.0(postcss@8.5.26) + postcss-simple-vars: 7.0.1(postcss@8.5.26) + sugarss: 5.0.1(postcss@8.5.26) tinyglobby: 0.2.17 - postcss-nested@7.0.2(postcss@8.5.23): + postcss-nested@7.0.2(postcss@8.5.26): dependencies: - postcss: 8.5.23 + postcss: 8.5.26 postcss-selector-parser: 7.1.1 - postcss-preset-mantine@1.18.0(postcss@8.5.23): + postcss-preset-mantine@1.18.0(postcss@8.5.26): dependencies: - postcss: 8.5.23 - postcss-mixins: 12.1.2(postcss@8.5.23) - postcss-nested: 7.0.2(postcss@8.5.23) + postcss: 8.5.26 + postcss-mixins: 12.1.2(postcss@8.5.26) + postcss-nested: 7.0.2(postcss@8.5.26) postcss-selector-parser@7.1.1: dependencies: cssesc: 3.0.0 util-deprecate: 1.0.2 - postcss-simple-vars@7.0.1(postcss@8.5.23): + postcss-simple-vars@7.0.1(postcss@8.5.26): dependencies: - postcss: 8.5.23 + postcss: 8.5.26 postcss@8.5.23: dependencies: @@ -6387,6 +6418,12 @@ snapshots: picocolors: 1.1.1 source-map-js: 1.2.1 + postcss@8.5.26: + dependencies: + nanoid: 3.3.18 + picocolors: 1.1.1 + source-map-js: 1.2.1 + prelude-ls@1.2.1: {} prettier-linter-helpers@1.0.1: @@ -6449,43 +6486,43 @@ snapshots: react: 19.2.8 react-dom: 19.2.8(react@19.2.8) - react-redux@9.3.0(@types/react@19.2.17)(react@19.2.8)(redux@5.0.1): + react-redux@9.3.0(@types/react@19.2.18)(react@19.2.8)(redux@5.0.1): dependencies: '@types/use-sync-external-store': 0.0.6 react: 19.2.8 use-sync-external-store: 1.6.0(react@19.2.8) optionalDependencies: - '@types/react': 19.2.17 + '@types/react': 19.2.18 redux: 5.0.1 react-refresh@0.17.0: {} - react-remove-scroll-bar@2.3.8(@types/react@19.2.17)(react@19.2.8): + react-remove-scroll-bar@2.3.8(@types/react@19.2.18)(react@19.2.8): dependencies: react: 19.2.8 - react-style-singleton: 2.2.3(@types/react@19.2.17)(react@19.2.8) + react-style-singleton: 2.2.3(@types/react@19.2.18)(react@19.2.8) tslib: 2.8.1 optionalDependencies: - '@types/react': 19.2.17 + '@types/react': 19.2.18 - react-remove-scroll@2.7.2(@types/react@19.2.17)(react@19.2.8): + react-remove-scroll@2.7.2(@types/react@19.2.18)(react@19.2.8): dependencies: react: 19.2.8 - react-remove-scroll-bar: 2.3.8(@types/react@19.2.17)(react@19.2.8) - react-style-singleton: 2.2.3(@types/react@19.2.17)(react@19.2.8) + react-remove-scroll-bar: 2.3.8(@types/react@19.2.18)(react@19.2.8) + react-style-singleton: 2.2.3(@types/react@19.2.18)(react@19.2.8) tslib: 2.8.1 - use-callback-ref: 1.3.3(@types/react@19.2.17)(react@19.2.8) - use-sidecar: 1.1.3(@types/react@19.2.17)(react@19.2.8) + use-callback-ref: 1.3.3(@types/react@19.2.18)(react@19.2.8) + use-sidecar: 1.1.3(@types/react@19.2.18)(react@19.2.8) optionalDependencies: - '@types/react': 19.2.17 + '@types/react': 19.2.18 - react-router-dom@7.18.1(react-dom@19.2.8(react@19.2.8))(react@19.2.8): + react-router-dom@7.18.2(react-dom@19.2.8(react@19.2.8))(react@19.2.8): dependencies: react: 19.2.8 react-dom: 19.2.8(react@19.2.8) - react-router: 7.18.1(react-dom@19.2.8(react@19.2.8))(react@19.2.8) + react-router: 7.18.2(react-dom@19.2.8(react@19.2.8))(react@19.2.8) - react-router@7.18.1(react-dom@19.2.8(react@19.2.8))(react@19.2.8): + react-router@7.18.2(react-dom@19.2.8(react@19.2.8))(react@19.2.8): dependencies: cookie: 1.1.1 react: 19.2.8 @@ -6493,13 +6530,13 @@ snapshots: optionalDependencies: react-dom: 19.2.8(react@19.2.8) - react-style-singleton@2.2.3(@types/react@19.2.17)(react@19.2.8): + react-style-singleton@2.2.3(@types/react@19.2.18)(react@19.2.8): dependencies: get-nonce: 1.0.1 react: 19.2.8 tslib: 2.8.1 optionalDependencies: - '@types/react': 19.2.17 + '@types/react': 19.2.18 react-transition-group@4.4.5(react-dom@19.2.8(react@19.2.8))(react@19.2.8): dependencies: @@ -6542,7 +6579,7 @@ snapshots: path-parse: 1.0.7 supports-preserve-symlinks-flag: 1.0.0 - rollup-plugin-license@3.7.1(picomatch@4.0.4)(rollup@4.62.3): + rollup-plugin-license@3.7.1(picomatch@4.0.4)(rollup@4.62.4): dependencies: commenting: 1.1.0 fdir: 6.5.0(picomatch@4.0.4) @@ -6550,41 +6587,42 @@ snapshots: magic-string: 0.30.21 moment: 2.30.1 package-name-regex: 2.0.6 - rollup: 4.62.3 + rollup: 4.62.4 spdx-expression-validate: 2.0.0 spdx-satisfies: 5.0.1 transitivePeerDependencies: - picomatch - rollup@4.62.3: + rollup@4.62.4: dependencies: '@types/estree': 1.0.9 optionalDependencies: - '@rollup/rollup-android-arm-eabi': 4.62.3 - '@rollup/rollup-android-arm64': 4.62.3 - '@rollup/rollup-darwin-arm64': 4.62.3 - '@rollup/rollup-darwin-x64': 4.62.3 - '@rollup/rollup-freebsd-arm64': 4.62.3 - '@rollup/rollup-freebsd-x64': 4.62.3 - '@rollup/rollup-linux-arm-gnueabihf': 4.62.3 - '@rollup/rollup-linux-arm-musleabihf': 4.62.3 - '@rollup/rollup-linux-arm64-gnu': 4.62.3 - '@rollup/rollup-linux-arm64-musl': 4.62.3 - '@rollup/rollup-linux-loong64-gnu': 4.62.3 - '@rollup/rollup-linux-loong64-musl': 4.62.3 - '@rollup/rollup-linux-ppc64-gnu': 4.62.3 - '@rollup/rollup-linux-ppc64-musl': 4.62.3 - '@rollup/rollup-linux-riscv64-gnu': 4.62.3 - '@rollup/rollup-linux-riscv64-musl': 4.62.3 - '@rollup/rollup-linux-s390x-gnu': 4.62.3 - '@rollup/rollup-linux-x64-gnu': 4.62.3 - '@rollup/rollup-linux-x64-musl': 4.62.3 - '@rollup/rollup-openbsd-x64': 4.62.3 - '@rollup/rollup-openharmony-arm64': 4.62.3 - '@rollup/rollup-win32-arm64-msvc': 4.62.3 - '@rollup/rollup-win32-ia32-msvc': 4.62.3 - '@rollup/rollup-win32-x64-gnu': 4.62.3 - '@rollup/rollup-win32-x64-msvc': 4.62.3 + '@napi-rs/lzma-linux-x64-gnu': 1.5.1 + '@rollup/rollup-android-arm-eabi': 4.62.4 + '@rollup/rollup-android-arm64': 4.62.4 + '@rollup/rollup-darwin-arm64': 4.62.4 + '@rollup/rollup-darwin-x64': 4.62.4 + '@rollup/rollup-freebsd-arm64': 4.62.4 + '@rollup/rollup-freebsd-x64': 4.62.4 + '@rollup/rollup-linux-arm-gnueabihf': 4.62.4 + '@rollup/rollup-linux-arm-musleabihf': 4.62.4 + '@rollup/rollup-linux-arm64-gnu': 4.62.4 + '@rollup/rollup-linux-arm64-musl': 4.62.4 + '@rollup/rollup-linux-loong64-gnu': 4.62.4 + '@rollup/rollup-linux-loong64-musl': 4.62.4 + '@rollup/rollup-linux-ppc64-gnu': 4.62.4 + '@rollup/rollup-linux-ppc64-musl': 4.62.4 + '@rollup/rollup-linux-riscv64-gnu': 4.62.4 + '@rollup/rollup-linux-riscv64-musl': 4.62.4 + '@rollup/rollup-linux-s390x-gnu': 4.62.4 + '@rollup/rollup-linux-x64-gnu': 4.62.4 + '@rollup/rollup-linux-x64-musl': 4.62.4 + '@rollup/rollup-openbsd-x64': 4.62.4 + '@rollup/rollup-openharmony-arm64': 4.62.4 + '@rollup/rollup-win32-arm64-msvc': 4.62.4 + '@rollup/rollup-win32-ia32-msvc': 4.62.4 + '@rollup/rollup-win32-x64-gnu': 4.62.4 + '@rollup/rollup-win32-x64-msvc': 4.62.4 fsevents: 2.3.3 rrweb-cssom@0.7.1: {} @@ -6601,7 +6639,7 @@ snapshots: is-plain-object: 5.0.0 launder: 1.7.1 parse-srcset: 1.0.2 - postcss: 8.5.23 + postcss: 8.5.26 saxes@6.0.0: dependencies: @@ -6720,9 +6758,9 @@ snapshots: style-mod@4.1.3: {} - sugarss@5.0.1(postcss@8.5.23): + sugarss@5.0.1(postcss@8.5.26): dependencies: - postcss: 8.5.23 + postcss: 8.5.26 supports-color@7.2.0: dependencies: @@ -6740,7 +6778,7 @@ snapshots: dependencies: '@pkgr/core': 0.3.6 - tabbable@6.4.0: {} + tabbable@6.5.0: {} tagged-tag@1.0.0: {} @@ -6793,12 +6831,12 @@ snapshots: dependencies: typescript: 5.9.3 - ts-jest@29.4.12(@babel/core@7.29.7)(@jest/transform@30.4.1)(@jest/types@30.4.1)(babel-jest@30.4.1(@babel/core@7.29.7))(jest-util@30.4.1)(jest@30.4.2(@types/node@26.0.1))(typescript@5.9.3): + ts-jest@29.4.12(@babel/core@7.29.7(supports-color@8.1.1))(@jest/transform@30.4.1(supports-color@8.1.1))(@jest/types@30.4.1)(babel-jest@30.4.1(@babel/core@7.29.7(supports-color@8.1.1))(supports-color@8.1.1))(esbuild@0.25.12)(jest-util@30.4.1)(jest@30.4.2(@types/node@26.0.1)(supports-color@8.1.1))(typescript@5.9.3): dependencies: bs-logger: 0.2.6 fast-json-stable-stringify: 2.1.0 handlebars: 4.7.9 - jest: 30.4.2(@types/node@26.0.1) + jest: 30.4.2(@types/node@26.0.1)(supports-color@8.1.1) json5: 2.2.3 lodash.memoize: 4.1.2 make-error: 1.3.6 @@ -6807,10 +6845,11 @@ snapshots: typescript: 5.9.3 yargs-parser: 21.1.1 optionalDependencies: - '@babel/core': 7.29.7 - '@jest/transform': 30.4.1 + '@babel/core': 7.29.7(supports-color@8.1.1) + '@jest/transform': 30.4.1(supports-color@8.1.1) '@jest/types': 30.4.1 - babel-jest: 30.4.1(@babel/core@7.29.7) + babel-jest: 30.4.1(@babel/core@7.29.7(supports-color@8.1.1))(supports-color@8.1.1) + esbuild: 0.25.12 jest-util: 30.4.1 tslib@2.8.1: {} @@ -6880,28 +6919,28 @@ snapshots: dependencies: punycode: 2.3.1 - use-callback-ref@1.3.3(@types/react@19.2.17)(react@19.2.8): + use-callback-ref@1.3.3(@types/react@19.2.18)(react@19.2.8): dependencies: react: 19.2.8 tslib: 2.8.1 optionalDependencies: - '@types/react': 19.2.17 + '@types/react': 19.2.18 - use-query-params@2.2.2(react-dom@19.2.8(react@19.2.8))(react-router-dom@7.18.1(react-dom@19.2.8(react@19.2.8))(react@19.2.8))(react@19.2.8): + use-query-params@2.2.2(react-dom@19.2.8(react@19.2.8))(react-router-dom@7.18.2(react-dom@19.2.8(react@19.2.8))(react@19.2.8))(react@19.2.8): dependencies: react: 19.2.8 react-dom: 19.2.8(react@19.2.8) serialize-query-params: 2.0.4 optionalDependencies: - react-router-dom: 7.18.1(react-dom@19.2.8(react@19.2.8))(react@19.2.8) + react-router-dom: 7.18.2(react-dom@19.2.8(react@19.2.8))(react@19.2.8) - use-sidecar@1.1.3(@types/react@19.2.17)(react@19.2.8): + use-sidecar@1.1.3(@types/react@19.2.18)(react@19.2.8): dependencies: detect-node-es: 1.1.0 react: 19.2.8 tslib: 2.8.1 optionalDependencies: - '@types/react': 19.2.17 + '@types/react': 19.2.18 use-sync-external-store@1.6.0(react@19.2.8): dependencies: @@ -6915,13 +6954,13 @@ snapshots: '@types/istanbul-lib-coverage': 2.0.6 convert-source-map: 2.0.0 - vite-node@3.2.4(@types/node@26.0.1)(sugarss@5.0.1(postcss@8.5.23)): + vite-node@3.2.4(@types/node@26.0.1)(sugarss@5.0.1(postcss@8.5.26))(supports-color@8.1.1): dependencies: cac: 6.7.14 - debug: 4.4.3 + debug: 4.4.3(supports-color@8.1.1) es-module-lexer: 1.7.0 pathe: 2.0.3 - vite: 6.4.3(@types/node@26.0.1)(sugarss@5.0.1(postcss@8.5.23)) + vite: 6.4.3(@types/node@26.0.1)(sugarss@5.0.1(postcss@8.5.26)) transitivePeerDependencies: - '@types/node' - jiti @@ -6936,31 +6975,31 @@ snapshots: - tsx - yaml - vite@6.4.3(@types/node@26.0.1)(sugarss@5.0.1(postcss@8.5.23)): + vite@6.4.3(@types/node@26.0.1)(sugarss@5.0.1(postcss@8.5.26)): dependencies: esbuild: 0.25.12 fdir: 6.5.0(picomatch@4.0.4) picomatch: 4.0.4 postcss: 8.5.23 - rollup: 4.62.3 + rollup: 4.62.4 tinyglobby: 0.2.17 optionalDependencies: '@types/node': 26.0.1 fsevents: 2.3.3 - sugarss: 5.0.1(postcss@8.5.23) + sugarss: 5.0.1(postcss@8.5.26) - vitest@3.2.7(@types/node@26.0.1)(jsdom@25.0.1)(sugarss@5.0.1(postcss@8.5.23)): + vitest@3.2.7(@types/node@26.0.1)(jsdom@25.0.1(supports-color@8.1.1))(sugarss@5.0.1(postcss@8.5.26))(supports-color@8.1.1): dependencies: '@types/chai': 5.2.3 '@vitest/expect': 3.2.7 - '@vitest/mocker': 3.2.7(vite@6.4.3(@types/node@26.0.1)(sugarss@5.0.1(postcss@8.5.23))) + '@vitest/mocker': 3.2.7(vite@6.4.3(@types/node@26.0.1)(sugarss@5.0.1(postcss@8.5.26))) '@vitest/pretty-format': 3.2.7 '@vitest/runner': 3.2.7 '@vitest/snapshot': 3.2.7 '@vitest/spy': 3.2.7 '@vitest/utils': 3.2.7 chai: 5.3.3 - debug: 4.4.3 + debug: 4.4.3(supports-color@8.1.1) expect-type: 1.3.0 magic-string: 0.30.21 pathe: 2.0.3 @@ -6971,12 +7010,12 @@ snapshots: tinyglobby: 0.2.17 tinypool: 1.1.1 tinyrainbow: 2.0.0 - vite: 6.4.3(@types/node@26.0.1)(sugarss@5.0.1(postcss@8.5.23)) - vite-node: 3.2.4(@types/node@26.0.1)(sugarss@5.0.1(postcss@8.5.23)) + vite: 6.4.3(@types/node@26.0.1)(sugarss@5.0.1(postcss@8.5.26)) + vite-node: 3.2.4(@types/node@26.0.1)(sugarss@5.0.1(postcss@8.5.26))(supports-color@8.1.1) why-is-node-running: 2.3.0 optionalDependencies: '@types/node': 26.0.1 - jsdom: 25.0.1 + jsdom: 25.0.1(supports-color@8.1.1) transitivePeerDependencies: - jiti - less diff --git a/web/ui/react-app/config-overrides.js b/web/ui/react-app/config-overrides.js index 53e36a625f0..600a50e0dbd 100644 --- a/web/ui/react-app/config-overrides.js +++ b/web/ui/react-app/config-overrides.js @@ -33,7 +33,7 @@ const singletons = [ '@lezer/lr', ]; -module.exports = function override(config) { +function override(config) { config.resolve = config.resolve || {}; config.resolve.alias = Object.assign( {}, @@ -47,4 +47,21 @@ module.exports = function override(config) { (plugin) => !(plugin.constructor && plugin.constructor.name === 'ModuleScopePlugin') ); return config; +} + +override.jest = function overrideJest(config) { + config.moduleNameMapper = Object.assign( + {}, + config.moduleNameMapper, + Object.fromEntries(singletons.map((pkg) => [`^${pkg}$`, `/node_modules/${pkg}`])) + ); + // Jest 27 does not honor conditional CommonJS exports for these dependencies, + // so transpile their ESM entrypoints while leaving other node modules untouched. + config.transformIgnorePatterns = [ + '/node_modules/(?!(@prometheus-io/(codemirror-promql|lezer-promql)|\\.pnpm/(@marijn\\+find-cluster-break|dom-serializer|domelementtype|domhandler|domutils|entities|htmlparser2)@)).+\\.(js|jsx|mjs|cjs|ts|tsx)$', + '^.+\\.module\\.(css|sass|scss)$', + ]; + return config; }; + +module.exports = override; diff --git a/web/ui/react-app/package.json b/web/ui/react-app/package.json index bdde751e7b4..dcf117b3bde 100644 --- a/web/ui/react-app/package.json +++ b/web/ui/react-app/package.json @@ -30,13 +30,12 @@ "moment": "^2.30.1", "moment-timezone": "^0.6.3", "popper.js": "^1.16.1", - "react": "^17.0.2", + "react": "^18.3.1", "react-copy-to-clipboard": "^5.1.1", - "react-dom": "^17.0.2", + "react-dom": "^18.3.1", "react-infinite-scroll-component": "^6.1.1", "react-resize-detector": "^7.1.2", - "react-router-dom": "^5.3.4", - "react-test-renderer": "^17.0.2", + "react-router-dom": "^7.0.0", "reactstrap": "^8.10.1", "sanitize-html": "^2.17.6", "sass": "1.102.0", @@ -67,44 +66,42 @@ ], "devDependencies": { "@babel/plugin-proposal-private-property-in-object": "^7.21.11", - "@testing-library/react-hooks": "^8.0.1", + "@cfaester/enzyme-adapter-react-18": "^0.8.0", + "@testing-library/dom": "^10.4.1", + "@testing-library/react": "^16.3.2", "@types/enzyme": "^3.10.19", "@types/flot": "0.0.36", "@types/jest": "^29.5.14", "@types/jquery": "^3.5.34", "@types/node": "^22.20.1", - "@types/react": "^17.0.93", + "@types/react": "^18.3.31", "@types/react-copy-to-clipboard": "^5.0.7", - "@types/react-dom": "^17.0.26", - "@types/react-router-dom": "^5.3.3", + "@types/react-dom": "^18.3.7", "@types/sanitize-html": "^2.16.1", "@types/sinon": "^17.0.4", - "@wojtekmaj/enzyme-adapter-react-17": "^0.8.0", "enzyme": "^3.11.0", "enzyme-to-json": "^3.6.2", "eslint": "^8.57.1", "eslint-config-prettier": "^10.1.8", "eslint-config-react-app": "^7.0.1", "eslint-plugin-prettier": "^5.5.6", + "identity-obj-proxy": "^3.0.0", "jest-canvas-mock": "^2.5.8", "jest-fetch-mock": "^3.2.0", "mutationobserver-shim": "^0.3.7", "prettier": "^3.9.6", "react-app-rewired": "^2.2.1", + "react-router": "^7.0.0", "react-scripts": "^5.0.1", - "sinon": "^19.0.5", - "ts-jest": "^29.4.12" + "sinon": "^19.0.5" }, "jest": { "snapshotSerializers": [ "enzyme-to-json/serializer" ], - "transformIgnorePatterns": [ - "/node_modules/(?!@prometheus-io/codemirror-promql)/", - "/node_modules/(?!@prometheus-io/lezer-promql)/" - ], "moduleNameMapper": { - "lezer-promql": "/node_modules/@prometheus-io/lezer-promql/dist/index.cjs" + "^react-router/dom$": "/node_modules/react-router/dist/development/dom-export.js", + "^(@prometheus-io/)?lezer-promql$": "/../module/lezer-promql/dist/index.cjs" } }, "optionalDependencies": { diff --git a/web/ui/react-app/pnpm-lock.yaml b/web/ui/react-app/pnpm-lock.yaml index 4890491037c..e3c37a16287 100644 --- a/web/ui/react-app/pnpm-lock.yaml +++ b/web/ui/react-app/pnpm-lock.yaml @@ -4,6 +4,9 @@ settings: autoInstallPeers: true excludeLinksFromLockfile: false +overrides: + enzyme>cheerio: 1.0.0-rc.12 + importers: .: @@ -28,7 +31,7 @@ importers: version: 6.7.1 '@codemirror/view': specifier: ^6.43.6 - version: 6.43.6 + version: 6.43.8 '@forevolve/bootstrap-dark': specifier: ^4.0.2 version: 4.0.2 @@ -43,7 +46,7 @@ importers: version: 6.7.2 '@fortawesome/react-fontawesome': specifier: 0.2.6 - version: 0.2.6(@fortawesome/fontawesome-svg-core@6.7.2)(react@17.0.2) + version: 0.2.6(@fortawesome/fontawesome-svg-core@6.7.2)(react@18.3.1) '@lezer/common': specifier: ^1.5.2 version: 1.5.2 @@ -70,10 +73,10 @@ importers: version: 1.5.1 downshift: specifier: ^9.4.0 - version: 9.4.0(react@17.0.2) + version: 9.4.0(react@18.3.1) http-proxy-middleware: specifier: ^3.0.7 - version: 3.0.7 + version: 3.0.7(supports-color@8.1.1) jquery: specifier: ^3.7.1 version: 3.7.1 @@ -90,29 +93,26 @@ importers: specifier: ^1.16.1 version: 1.16.1 react: - specifier: ^17.0.2 - version: 17.0.2 + specifier: ^18.3.1 + version: 18.3.1 react-copy-to-clipboard: specifier: ^5.1.1 - version: 5.1.1(react@17.0.2) + version: 5.1.1(react@18.3.1) react-dom: - specifier: ^17.0.2 - version: 17.0.2(react@17.0.2) + specifier: ^18.3.1 + version: 18.3.1(react@18.3.1) react-infinite-scroll-component: specifier: ^6.1.1 - version: 6.1.1(react@17.0.2) + version: 6.1.1(react@18.3.1) react-resize-detector: specifier: ^7.1.2 - version: 7.1.2(react-dom@17.0.2(react@17.0.2))(react@17.0.2) + version: 7.1.2(react-dom@18.3.1(react@18.3.1))(react@18.3.1) react-router-dom: - specifier: ^5.3.4 - version: 5.3.4(react@17.0.2) - react-test-renderer: - specifier: ^17.0.2 - version: 17.0.2(react@17.0.2) + specifier: ^7.0.0 + version: 7.18.2(react-dom@18.3.1(react@18.3.1))(react@18.3.1) reactstrap: specifier: ^8.10.1 - version: 8.10.1(react-dom@17.0.2(react@17.0.2))(react@17.0.2) + version: 8.10.1(react-dom@18.3.1(react@18.3.1))(react@18.3.1) sanitize-html: specifier: ^2.17.6 version: 2.17.6 @@ -128,10 +128,16 @@ importers: devDependencies: '@babel/plugin-proposal-private-property-in-object': specifier: ^7.21.11 - version: 7.21.11(@babel/core@7.29.7) - '@testing-library/react-hooks': - specifier: ^8.0.1 - version: 8.0.1(@types/react@17.0.93)(react-dom@17.0.2(react@17.0.2))(react-test-renderer@17.0.2(react@17.0.2))(react@17.0.2) + version: 7.21.11(@babel/core@7.29.7(supports-color@8.1.1))(supports-color@8.1.1) + '@cfaester/enzyme-adapter-react-18': + specifier: ^0.8.0 + version: 0.8.0(enzyme@3.11.0)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) + '@testing-library/dom': + specifier: ^10.4.1 + version: 10.4.1 + '@testing-library/react': + specifier: ^16.3.2 + version: 16.3.2(@testing-library/dom@10.4.1)(@types/react-dom@18.3.7(@types/react@18.3.31))(@types/react@18.3.31)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) '@types/enzyme': specifier: ^3.10.19 version: 3.10.19 @@ -148,26 +154,20 @@ importers: specifier: ^22.20.1 version: 22.20.1 '@types/react': - specifier: ^17.0.93 - version: 17.0.93 + specifier: ^18.3.31 + version: 18.3.31 '@types/react-copy-to-clipboard': specifier: ^5.0.7 version: 5.0.7 '@types/react-dom': - specifier: ^17.0.26 - version: 17.0.26(@types/react@17.0.93) - '@types/react-router-dom': - specifier: ^5.3.3 - version: 5.3.3 + specifier: ^18.3.7 + version: 18.3.7(@types/react@18.3.31) '@types/sanitize-html': specifier: ^2.16.1 version: 2.16.1 '@types/sinon': specifier: ^17.0.4 version: 17.0.4 - '@wojtekmaj/enzyme-adapter-react-17': - specifier: ^0.8.0 - version: 0.8.0(enzyme@3.11.0)(react-dom@17.0.2(react@17.0.2))(react@17.0.2) enzyme: specifier: ^3.11.0 version: 3.11.0 @@ -176,16 +176,19 @@ importers: version: 3.6.2(enzyme@3.11.0) eslint: specifier: ^8.57.1 - version: 8.57.1 + version: 8.57.1(supports-color@8.1.1) eslint-config-prettier: specifier: ^10.1.8 - version: 10.1.8(eslint@8.57.1) + version: 10.1.8(eslint@8.57.1(supports-color@8.1.1)) eslint-config-react-app: specifier: ^7.0.1 - version: 7.0.1(@babel/plugin-syntax-flow@7.29.7(@babel/core@7.29.7))(@babel/plugin-transform-react-jsx@7.29.7(@babel/core@7.29.7))(eslint@8.57.1)(jest@27.5.1)(typescript@4.9.5) + version: 7.0.1(@babel/plugin-syntax-flow@7.29.7(@babel/core@7.29.7(supports-color@8.1.1)))(@babel/plugin-transform-react-jsx@7.29.7(@babel/core@7.29.7(supports-color@8.1.1))(supports-color@8.1.1))(eslint@8.57.1(supports-color@8.1.1))(jest@27.5.1(supports-color@8.1.1))(supports-color@8.1.1)(typescript@4.9.5) eslint-plugin-prettier: specifier: ^5.5.6 - version: 5.5.6(@types/eslint@8.56.12)(eslint-config-prettier@10.1.8(eslint@8.57.1))(eslint@8.57.1)(prettier@3.9.6) + version: 5.5.6(@types/eslint@8.56.12)(eslint-config-prettier@10.1.8(eslint@8.57.1(supports-color@8.1.1)))(eslint@8.57.1(supports-color@8.1.1))(prettier@3.9.6) + identity-obj-proxy: + specifier: ^3.0.0 + version: 3.0.0 jest-canvas-mock: specifier: ^2.5.8 version: 2.5.8 @@ -200,16 +203,16 @@ importers: version: 3.9.6 react-app-rewired: specifier: ^2.2.1 - version: 2.2.1(react-scripts@5.0.1(@babel/plugin-syntax-flow@7.29.7(@babel/core@7.29.7))(@babel/plugin-transform-react-jsx@7.29.7(@babel/core@7.29.7))(@types/babel__core@7.20.5)(eslint@8.57.1)(react@17.0.2)(sass@1.102.0)(type-fest@4.41.0)(typescript@4.9.5)) + version: 2.2.1(react-scripts@5.0.1(@babel/plugin-syntax-flow@7.29.7(@babel/core@7.29.7(supports-color@8.1.1)))(@babel/plugin-transform-react-jsx@7.29.7(@babel/core@7.29.7(supports-color@8.1.1))(supports-color@8.1.1))(@types/babel__core@7.20.5)(clean-css@5.3.3)(cssnano@5.1.15(postcss@8.5.15))(csso@4.2.0)(debug@4.4.3(supports-color@8.1.1))(eslint@8.57.1(supports-color@8.1.1))(html-minifier-terser@6.1.0)(react@18.3.1)(sass@1.102.0)(supports-color@8.1.1)(type-fest@4.41.0)(typescript@4.9.5)(uglify-js@3.19.3)) + react-router: + specifier: ^7.0.0 + version: 7.18.2(react-dom@18.3.1(react@18.3.1))(react@18.3.1) react-scripts: specifier: ^5.0.1 - version: 5.0.1(@babel/plugin-syntax-flow@7.29.7(@babel/core@7.29.7))(@babel/plugin-transform-react-jsx@7.29.7(@babel/core@7.29.7))(@types/babel__core@7.20.5)(eslint@8.57.1)(react@17.0.2)(sass@1.102.0)(type-fest@4.41.0)(typescript@4.9.5) + version: 5.0.1(@babel/plugin-syntax-flow@7.29.7(@babel/core@7.29.7(supports-color@8.1.1)))(@babel/plugin-transform-react-jsx@7.29.7(@babel/core@7.29.7(supports-color@8.1.1))(supports-color@8.1.1))(@types/babel__core@7.20.5)(clean-css@5.3.3)(cssnano@5.1.15(postcss@8.5.15))(csso@4.2.0)(debug@4.4.3(supports-color@8.1.1))(eslint@8.57.1(supports-color@8.1.1))(html-minifier-terser@6.1.0)(react@18.3.1)(sass@1.102.0)(supports-color@8.1.1)(type-fest@4.41.0)(typescript@4.9.5)(uglify-js@3.19.3) sinon: specifier: ^19.0.5 version: 19.0.5 - ts-jest: - specifier: ^29.4.12 - version: 29.4.12(@babel/core@7.29.7)(@jest/types@29.6.3)(jest-util@29.7.0)(jest@27.5.1)(typescript@4.9.5) optionalDependencies: fsevents: specifier: ^2.3.3 @@ -943,6 +946,13 @@ packages: '@bcoe/v8-coverage@0.2.3': resolution: {integrity: sha512-0hYQ8SB4Db5zvZB4axdMHGwEaQjkZzFjQiN9LVYvIFB2nSUHW9tYpxWriPrWDASIxiaXax83REcLxuSdnGPZtw==} + '@cfaester/enzyme-adapter-react-18@0.8.0': + resolution: {integrity: sha512-3Z3ThTUouHwz8oIyhTYQljEMNRFtlVyc3VOOHCbxs47U6cnXs8K9ygi/c1tv49s7MBlTXeIcuN+Ttd9aPtILFQ==} + peerDependencies: + enzyme: ^3.11.0 + react: '>=18' + react-dom: '>=18' + '@codemirror/autocomplete@6.20.3': resolution: {integrity: sha512-tlosUqb+3BbxCxZdu4tKeRghPFC+QM7q4X5YhKV2eCmPG+1r2F3f4AaSz5sCrFqUtX4Jh20VFTKecl16MgiV9g==} @@ -961,8 +971,8 @@ packages: '@codemirror/state@6.7.1': resolution: {integrity: sha512-9QzNDgE4EYDnAHfrTlR2lwiPciiOymLtwKK+8yHQzCc7GXhAP9xdEbEJFy2IWB1j9UGUl9BsgMmTo/ImA02T7A==} - '@codemirror/view@6.43.6': - resolution: {integrity: sha512-EVunGSYN1wz1p75WY1s3Xg7t3i8Yol0kGZGizNdX9BUFgMFILYVe8/u6EVpo7Ff5PwbZuILb4QAq7IZoKzIEQA==} + '@codemirror/view@6.43.8': + resolution: {integrity: sha512-qtItTDssZ/5GFfi94hrILu9j/VUeFPDPkhovEfmWFj2ipTxnzPB8DdHgfbb8HYTzLTYhrndKmyQxXUz/PDLenw==} '@csstools/normalize.css@12.1.1': resolution: {integrity: sha512-YAYeJ+Xqh7fUou1d1j9XHl44BmsuThiTr4iNrgCQ3J27IbhXsxXDGZ1cXv8Qvs99d4rBbLiSKy3+WZiet32PcQ==} @@ -1496,26 +1506,32 @@ packages: resolution: {integrity: sha512-DOBOK255wfQxguUta2INKkzPj6AIS6iafZYiYmHn6W3pHlycSRRlvWKCfLDG10fXfLWqE3DJHgRUOyJYmARa7g==} engines: {node: '>=10'} - '@testing-library/react-hooks@8.0.1': - resolution: {integrity: sha512-Aqhl2IVmLt8IovEVarNDFuJDVWVvhnr9/GCU6UUnrYXwgDFF9h2L2o2P9KBni1AST5sT6riAyoukFLyjQUgD/g==} - engines: {node: '>=12'} + '@testing-library/dom@10.4.1': + resolution: {integrity: sha512-o4PXJQidqJl82ckFaXUeoAW+XysPLauYI43Abki5hABd853iMhitooc6znOnczgbTYmEP6U6/y1ZyKAIsvMKGg==} + engines: {node: '>=18'} + + '@testing-library/react@16.3.2': + resolution: {integrity: sha512-XU5/SytQM+ykqMnAnvB2umaJNIOsLF3PVv//1Ew4CTcpz0/BRyy/af40qqrt7SjKpDdT1saBMc42CUok5gaw+g==} + engines: {node: '>=18'} peerDependencies: - '@types/react': ^16.9.0 || ^17.0.0 - react: ^16.9.0 || ^17.0.0 - react-dom: ^16.9.0 || ^17.0.0 - react-test-renderer: ^16.9.0 || ^17.0.0 + '@testing-library/dom': ^10.0.0 + '@types/react': ^18.0.0 || ^19.0.0 + '@types/react-dom': ^18.0.0 || ^19.0.0 + react: ^18.0.0 || ^19.0.0 + react-dom: ^18.0.0 || ^19.0.0 peerDependenciesMeta: '@types/react': optional: true - react-dom: - optional: true - react-test-renderer: + '@types/react-dom': optional: true '@tootallnate/once@1.1.2': resolution: {integrity: sha512-RbzJvlNzmRq5c3O09UipeuXno4tA1FE6ikOjxZK0tuxVv3412l64l5t1W5pj4+rJq9vpkm/kwiR07aZXnsKPxw==} engines: {node: '>= 6'} + '@types/aria-query@5.0.4': + resolution: {integrity: sha512-rfT93uj5s0PRL7EzccGMs3brplhcrghnDoV26NqKhCAS1hVo+WdNsPvE/yb6ilfr5hi2MEk6d5EWJTKdxg8jVw==} + '@types/babel__core@7.20.5': resolution: {integrity: sha512-qoQprZvz5wQFJwMDqeseRXWv3rqMvhgpbXFfVyWhbx9X47POIA6i/+dXefEmZKoAgOaTdaIgNSMqMIU61yRyzA==} @@ -1570,9 +1586,6 @@ packages: '@types/graceful-fs@4.1.9': resolution: {integrity: sha512-olP3sd1qOEe5dXTSaFvQG+02VdRXcdytWLAZsAq1PecU8uqQAhkrnbli7DagjtXKW/Bl7YJbUsa8MPcuc8LHEQ==} - '@types/history@4.7.11': - resolution: {integrity: sha512-qjDJRrmvBMiTx+jyLxvLfJU7UznFuokDv4f3WRuriHKERccVpFU+8XMQUAbDzoiJCsmexxRExQeMwwCdamSKDA==} - '@types/html-minifier-terser@6.1.0': resolution: {integrity: sha512-oh/6byDPnL1zeNXFrDXFLyZjkr1MsBG667IM792caf1L2UPOOMf65NFzjUH/ltyfwjAGfs1rsX1eftK0jC/KIg==} @@ -1633,22 +1646,16 @@ packages: '@types/react-copy-to-clipboard@5.0.7': resolution: {integrity: sha512-Gft19D+as4M+9Whq1oglhmK49vqPhcLzk8WfvfLvaYMIPYanyfLy0+CwFucMJfdKoSFyySPmkkWn8/E6voQXjQ==} - '@types/react-dom@17.0.26': - resolution: {integrity: sha512-Z+2VcYXJwOqQ79HreLU/1fyQ88eXSSFh6I3JdrEHQIfYSI0kCQpTGvOrbE6jFGGYXKsHuwY9tBa/w5Uo6KzrEg==} + '@types/react-dom@18.3.7': + resolution: {integrity: sha512-MEe3UeoENYVFXzoXEWsvcpg6ZvlrFNlOQ7EOsvhI3CfAXwzPfO8Qwuxd40nepsYKqyyVQnTdEfv68q91yLcKrQ==} peerDependencies: - '@types/react': ^17.0.0 - - '@types/react-router-dom@5.3.3': - resolution: {integrity: sha512-kpqnYK4wcdm5UaWI3fLcELopqLrHgLqNsdpHauzlQktfkHL3npOSwtj1Uz9oKBAzs7lFtVkV8j83voAz2D8fhw==} - - '@types/react-router@5.1.20': - resolution: {integrity: sha512-jGjmu/ZqS7FjSH6owMcD5qpq19+1RS9DeVRqfl1FeBMxTDQAGwlMWOcs52NDoXaNKyG3d1cYQFMs9rCrb88o9Q==} + '@types/react': ^18.0.0 '@types/react@16.14.70': resolution: {integrity: sha512-DM5Q7rSx9G6QYcVvMgxvEurL5P06OxcDNUXrLxlpBzG4ccUewcBCmsztYbxJBobzO8RIwwmjoaD5OsKqdHDuYQ==} - '@types/react@17.0.93': - resolution: {integrity: sha512-KM4Ty/ZTLZupiYxZVAlP+InNJS3De6uBMdq0ePa6/04+eG9Y7ftnWfst1xTLQ5rwAhgHwQ4momt/O4KepdGBTw==} + '@types/react@18.3.31': + resolution: {integrity: sha512-vfEqpXTvwT91yhmwdfouStN2hSKwTvyRs8qpLfADyrq/kxDw0hZM7Wk9Ug1FELj8hIby+S/+kQCSRFF32nv2Qw==} '@types/resolve@1.17.1': resolution: {integrity: sha512-yy7HuzQhj0dhGpD8RLXSZWEkLsV9ibvxvi6EiJ3bkqLAO1RGo0WbkWQiwpRlSFymTJRz0d3k5LM3kkx8ArDbLw==} @@ -1819,18 +1826,6 @@ packages: '@webassemblyjs/wast-printer@1.14.1': resolution: {integrity: sha512-kPSSXE6De1XOR820C90RIo2ogvZG+c3KiHzqUoO/F34Y2shGzesfqv7o57xrxovZJH/MetF5UjroJ/R/3isoiw==} - '@wojtekmaj/enzyme-adapter-react-17@0.8.0': - resolution: {integrity: sha512-zeUGfQRziXW7R7skzNuJyi01ZwuKCH8WiBNnTgUJwdS/CURrJwAhWsfW7nG7E30ak8Pu3ZwD9PlK9skBfAoOBw==} - peerDependencies: - enzyme: ^3.0.0 - react: ^17.0.0-0 - react-dom: ^17.0.0-0 - - '@wojtekmaj/enzyme-adapter-utils@0.2.0': - resolution: {integrity: sha512-ZvZm9kZxZEKAbw+M1/Q3iDuqQndVoN8uLnxZ8bzxm7KgGTBejrGRoJAp8f1EN8eoO3iAjBNEQnTDW/H4Ekb0FQ==} - peerDependencies: - react: ^17.0.0-0 - '@xtuc/ieee754@1.2.0': resolution: {integrity: sha512-DX8nKgqcGwsc0eJSqYt5lwP4DH5FlHnmuWWBRy7X0NcaGR0ZtuyeESgMwTYVEtxmsNGY+qit4QYT/MIYTOTPeA==} @@ -1959,6 +1954,9 @@ packages: argparse@2.0.1: resolution: {integrity: sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==} + aria-query@5.3.0: + resolution: {integrity: sha512-b0P0sZPKtyu8HkeRAfCq0IfURZK+SuwMjY1UXGBU27wpAiTwQAIlq56IbIO+ytk/JjS1fMR14ee5WBBfKi5J6A==} + aria-query@5.3.2: resolution: {integrity: sha512-COROpnaoap1E2F000S62r6A60uHZnmlvomhfyT2DlTcrY1OrBKn2UhH7qn5wTC9zMvD0AY7csdPSNwKP+7WiQw==} engines: {node: '>= 0.4'} @@ -2176,10 +2174,6 @@ packages: engines: {node: ^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7} hasBin: true - bs-logger@0.2.6: - resolution: {integrity: sha512-pd8DCoxmbgc7hyPKOvxtqNcjYoOsABPQdcCUjGp3d42VR2CX1ORhk2A87oqqu5R1kk+76nsxZupkmyd+MVtCog==} - engines: {node: '>= 6'} - bser@2.1.1: resolution: {integrity: sha512-gQxTNE/GAfIIrmHLUE3oJyp5FO6HRBfhjnw4/wMmA63ZGDJnWBmgY/lyQBpnDUkGmAhbSe39tx2d/iTOAfglwQ==} @@ -2257,9 +2251,9 @@ packages: cheerio-select@2.1.0: resolution: {integrity: sha512-9v9kG0LvzrlcungtnJtpGNxY+fzECQKhK4EGJX2vByejiMX84MFNQw4UxPJl3bFbTMw+Dfs37XaIkCwTZfLh4g==} - cheerio@1.2.0: - resolution: {integrity: sha512-WDrybc/gKFpTYQutKIK6UvfcuxijIZfMfXaYm8NMsPQxSYvf+13fXUJ4rztGGbJcBQ/GF55gvrZ0Bc0bj/mqvg==} - engines: {node: '>=20.18.1'} + cheerio@1.0.0-rc.12: + resolution: {integrity: sha512-VqR8m68vM46BNnuZ5NtnGBKIE/DfN0cRIzg9n40EIq9NOv90ayxLBXA8fXC5gquFRGJSTRqBq25Jt2ECLR431Q==} + engines: {node: '>= 6'} chokidar@3.6.0: resolution: {integrity: sha512-7VT13fmjotKpGipCW9JEQAusEPE+Ei8nl6/g4FBAmIm0GOOLMua9NDDo/DWp0ZAxCr3cPq5ZpBqmPAQgDda2Pw==} @@ -2388,6 +2382,10 @@ packages: resolution: {integrity: sha512-yki5XnKuf750l50uGTllt6kKILY4nQ1eNIQatoXEByZ5dWgnKqbnqmTrBE5B4N7lrMJKQ2ytWMiTO2o0v6Ew/w==} engines: {node: '>= 0.6'} + cookie@1.1.1: + resolution: {integrity: sha512-ei8Aos7ja0weRpFzJnEA9UHJ/7XQmqglbRwnf2ATjcB9Wq874VKH9kfjjirM6UhU2/E5fFYadylyhFldcqSidQ==} + engines: {node: '>=18'} + copy-to-clipboard@3.3.3: resolution: {integrity: sha512-2KV8NhB5JqC3ky0r9PMCAZKbUHSwtEo4CwCs0KXgruG43gX5PMqDEBbVU4OUzw2MuAWUfsuFmWvEKG5QRfSnJA==} @@ -2414,6 +2412,9 @@ packages: crelt@1.0.6: resolution: {integrity: sha512-VQ2MBenTq1fWZUH9DJNGti7kKv6EeAuYr3cLwxUWhIu1baTaXh4Ib5W2CqHVqib4/MqbYGJqiL3Zb8GJZr3l4g==} + crelt@1.0.7: + resolution: {integrity: sha512-aK6BbWfhf4U/wCcLHKPJl/xa6VkVstRaPywWtMKGwuOLc/wZTyQYuoxgvZnNsBvv7Kg3YTBQYYBCggcviQczuA==} + cross-fetch@3.2.0: resolution: {integrity: sha512-Q+xVJLoGOeIMXZmbUK4HYk+69cQH6LudR0Vu/pRm2YlU/hDV9CiS0gKUMaWY5f2NeUH9C1nV3bsTlCo0FsTV1Q==} @@ -2652,6 +2653,10 @@ packages: resolution: {integrity: sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw==} engines: {node: '>= 0.8'} + dequal@2.0.3: + resolution: {integrity: sha512-0je+qPKHEMohvfRTCEo3CrPG6cAzAYgmzKyxRiYSSDkS6eGJdyVJm7WaYA5ECaAD9wLB2T4EEeymA5aFVcYXCA==} + engines: {node: '>=6'} + destroy@1.2.0: resolution: {integrity: sha512-2sJGJTaXIIaR1w4iJSNoN0hnMY7Gpc/n8D4qSCJw8QqFWXf7cuAgnEHxBpweaVcPevC2l3KpjYCx3NypQQgaJg==} engines: {node: '>= 0.8', npm: 1.2.8000 || >= 1.4.16} @@ -2709,6 +2714,9 @@ packages: resolution: {integrity: sha512-yS+Q5i3hBf7GBkd4KG8a7eBNNWNGLTaEwwYWUijIYM7zrlYDM0BFXHjjPWlWZ1Rg7UaddZeIDmi9jF3HmqiQ2w==} engines: {node: '>=6.0.0'} + dom-accessibility-api@0.5.16: + resolution: {integrity: sha512-X7BJ2yElsnOJ30pZF4uIIDfBEVgF4XEBxL9Bxhy6dnrm5hkzqmsWHGTiHqRiITNhMyFLyAiWndIJP7Z1NTteDg==} + dom-converter@0.2.0: resolution: {integrity: sha512-gd3ypIPfOMr9h5jIKq8E3sHOTCjeirnl0WK5ZdS1AW0Odt0b1PaWaHdJ4Qk4klv+YB9aJBS7mESXjFoDQPu6DA==} @@ -2828,9 +2836,6 @@ packages: resolution: {integrity: sha512-Q0n9HRi4m6JuGIV1eFlmvJB7ZEVxu93IrMyiMsGC0lrMJMWzRgx6WGquyfQgZVb31vhGgXnfmPNNXmxnOkRBrg==} engines: {node: '>= 0.8'} - encoding-sniffer@0.2.1: - resolution: {integrity: sha512-5gvq20T6vfpekVtqrYQsSCFZ1wEg5+wW0/QaZMWkFr6BqD3NfKs0rLCx4rrVlSWJeZb5NBJgVLswK/w2MWU+Gw==} - enhanced-resolve@5.22.0: resolution: {integrity: sha512-xYcDWrpELkFzz9SpZ3PlI6Eu6eD93Yf0WLDRxikGhWJ3MAir2SNZTIVCVZqZ/NUyx8AdMc2gT9C0gPiw18kG+A==} engines: {node: '>=10.13.0'} @@ -3387,11 +3392,6 @@ packages: handle-thing@2.0.1: resolution: {integrity: sha512-9Qn4yBxelxoh2Ow62nP+Ka/kMnOXRi8BXnRaUwezLNhqelnN49xKz4F/dPP8OYLxLxq6JDtZb2i9XznUQbNPTg==} - handlebars@4.7.9: - resolution: {integrity: sha512-4E71E0rpOaQuJR2A3xDZ+GM1HyWYv1clR58tC8emQNeQe3RH7MAzSbat+V0wG78LQBo6m6bzSG/L4pBuCsgnUQ==} - engines: {node: '>=0.4.7'} - hasBin: true - harmony-reflect@1.6.2: resolution: {integrity: sha512-HIp/n38R9kQjDEziXyDTuW3vvoxxyxjxFzXLrBr18uB47GnSt+G9D29fqrpM5ZkspMcPICud3XsBJQ4Y2URg8g==} @@ -3434,12 +3434,6 @@ packages: resolution: {integrity: sha512-F/1DnUGPopORZi0ni+CvrCgHQ5FyEAHRLSApuYWMmrbSwoN2Mn/7k+Gl38gJnR7yyDZk6WLXwiGod1JOWNDKGw==} hasBin: true - history@4.10.1: - resolution: {integrity: sha512-36nwAD620w12kuzPAsyINPWJqlNbij+hpK1k9XRloDtym8mxzGYl2c17LnV6IAGB2Dmg4tEa7G7DlawS0+qjew==} - - hoist-non-react-statics@3.3.2: - resolution: {integrity: sha512-/gGivxi8JPKWNm/W0jSmzcMPpfpPLc3dY/6GxhX2hQ9iGj3aDfklV4ET7NjKpSinLpJ5vafa9iiGIEZg10SfBw==} - hoopy@0.1.4: resolution: {integrity: sha512-HRcs+2mr52W0K+x8RzcLzuPPmVIKMSv97RGHy0Ea9y/mpcaK+xTrjICA04KAHi4GRzxliNqNJEFYWHghy3rSfQ==} engines: {node: '>= 6.0.0'} @@ -3488,6 +3482,9 @@ packages: htmlparser2@6.1.0: resolution: {integrity: sha512-gyyPk6rgonLFEDGoeRgQNaEUvdJ4ktTmmUh/h2t7s+M8oPpIPxgNACWa+6ESR57kXstwqPiCut0V8NRpcwgU7A==} + htmlparser2@8.0.2: + resolution: {integrity: sha512-GYdjWKDkbRLkZ5geuHs5NY1puJ+PXwP7+fHPRz06Eirsb9ugf6d8kkXav6ADhcODhFFPMIXyxkxSuMf3D6NCFA==} + http-deceiver@1.2.7: resolution: {integrity: sha512-LmpOGxTfbpgtGVxJrj5k7asXHCgNZp5nLfp+hWc8QQRqtb7fUy6kRY3BO1h9ddF6yIPYUARgxGOwB42DnxIaNw==} @@ -3765,9 +3762,6 @@ packages: resolution: {integrity: sha512-fKzAra0rGJUUBwGBgNkHZuToZcn+TtXHpeCgmkMJMMYx1sQDYaCSyjJBSCa2nH1DGm7s3n1oBnohoVTBaN7Lww==} engines: {node: '>=8'} - isarray@0.0.1: - resolution: {integrity: sha512-D2S+3GLxWH+uhrNEcoh/fnmYeP8E8/zHl644d/jdA0g2uyXvy3sb0qxotE+ne0LtccHknQzWwZEzhak7oJ0COQ==} - isarray@1.0.0: resolution: {integrity: sha512-VLghIWNM6ELQzo7zwmcg0NmTVyWKYjvIeM83yjp0wRDTmUnrM678fQbcKBo6n2CJEF0szoG//ytg+TKla89ALQ==} @@ -4186,6 +4180,10 @@ packages: lru-cache@5.1.1: resolution: {integrity: sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w==} + lz-string@1.5.0: + resolution: {integrity: sha512-h5bgJWpxJNswbU7qCrV0tIKQCaS3blPDrqKWx+QxzuzL1zGUzij9XCWLrSLsJPu5t+eWA/ycetzYAO5IOMcWAQ==} + hasBin: true + magic-string@0.25.9: resolution: {integrity: sha512-RmF0AsMzgt25qzqqLc1+MbHmhdx0ojF2Fvs4XnOqz2ZOBXzzkEwc/dJQZCYHAn7v1jbVOjAZfK8msRn4BxO4VQ==} @@ -4197,9 +4195,6 @@ packages: resolution: {integrity: sha512-hXdUTZYIVOt1Ex//jAQi+wTZZpUpwBj/0QsOzqegb3rGMMeJiSEu5xLHnYfBrRV4RH2+OCSOO95Is/7x1WJ4bw==} engines: {node: '>=10'} - make-error@1.3.6: - resolution: {integrity: sha512-s8UhlNe7vPKomQhC1qFelMokr/Sc3AgNbso3n74mVPA5LTZwkB9NlXf4XPamLxJE8h0gh73rM94xvwRT2CVInw==} - makeerror@1.0.12: resolution: {integrity: sha512-JmqCvUhmt43madlpFzG4BQzG2Z3m6tvQDNKdClZnO3VbIudJYmxsT0FNJMeiB2+JTSlTQTSbU8QdesVmwJcmLg==} @@ -4510,9 +4505,6 @@ packages: parse5-htmlparser2-tree-adapter@7.1.0: resolution: {integrity: sha512-ruw5xyKs6lrpo9x9rCZqZZnIUntICjQAd0Wsmp396Ul9lN/h+ifgVV1x1gZHi8euej6wTfpqX8j+BFQxF0NS/g==} - parse5-parser-stream@7.1.2: - resolution: {integrity: sha512-JyeQc9iwFLn5TbvvqACIF/VXG6abODeB3Fwmv/TGdLk2LfbWkaySGY72at4+Ty7EkPZj854u4CrICqNk2qIbow==} - parse5@6.0.1: resolution: {integrity: sha512-Ofn/CTFzRGTTxwpNEs9PP93gXShHcTq255nzRYSKe8AkVpZY7e1fpmTfOyoIvjP5HG7Z2ZM7VS9PPhQGW2pOpw==} @@ -4548,9 +4540,6 @@ packages: path-to-regexp@0.1.13: resolution: {integrity: sha512-A/AGNMFN3c8bOlvV9RreMdrv7jsmF9XIfDeCd87+I8RNg6s78BhJxMu69NEMHBSJFxKidViTEdruRwEk/WIKqA==} - path-to-regexp@1.9.0: - resolution: {integrity: sha512-xIp7/apCFJuUHdDLWe8O1HIkb0kQrOMb/0u6FXQjemHn/ii5LrIzU6bdECnsiTF/GjZkMEKg1xdiZwNqDYlZ6g==} - path-to-regexp@8.4.2: resolution: {integrity: sha512-qRcuIdP69NPm4qbACK+aDogI5CBDMi1jKe0ry5rSQJz8JVLsC7jV8XpiJjGRLLol3N+R5ihGYcrPLTno6pAdBA==} @@ -5155,16 +5144,10 @@ packages: typescript: optional: true - react-dom@17.0.2: - resolution: {integrity: sha512-s4h96KtLDUQlsENhMn1ar8t2bEa+q/YAtj8pPPdIjPDGBDIVNsrD9aXNWqspUe6AzKCIG0C1HZZLqLV7qpOBGA==} + react-dom@18.3.1: + resolution: {integrity: sha512-5m4nQKp+rZRb09LNH59GM4BxTh9251/ylbKIbpe7TpGxfJ+9kv6BLkLBXIjjspbgbnIBNqlI23tRnTWT0snUIw==} peerDependencies: - react: 17.0.2 - - react-error-boundary@3.1.4: - resolution: {integrity: sha512-uM9uPzZJTF6wRQORmSrvOIgt4lJ9MC1sNgEOj2XGsDTRE4kmpWxg7ENK9EWNKJRMAOY9z0MuF4yIfl6gp4sotA==} - engines: {node: '>=10', npm: '>=6'} - peerDependencies: - react: '>=16.13.1' + react: ^18.3.1 react-error-overlay@6.1.0: resolution: {integrity: sha512-SN/U6Ytxf1QGkw/9ve5Y+NxBbZM6Ht95tuXNMKs8EJyFa/Vy/+Co3stop3KBHARfn/giv+Lj1uUnTfOJ3moFEQ==} @@ -5201,15 +5184,22 @@ packages: react: ^16.0.0 || ^17.0.0 || ^18.0.0 react-dom: ^16.0.0 || ^17.0.0 || ^18.0.0 - react-router-dom@5.3.4: - resolution: {integrity: sha512-m4EqFMHv/Ih4kpcBCONHbkT68KoAeHN4p3lAGoNryfHi0dMy0kCzEZakiKRsvg5wHZ/JLrLW8o8KomWiz/qbYQ==} + react-router-dom@7.18.2: + resolution: {integrity: sha512-AIKJ/jgGlFb3EbfCXk5Gzshiwt+l3mqbCrNjmEWMMjqQxNJ3svBa6bgzFyCC2Sw3RA0VWF1kg3uQf2OFhxb8hw==} + engines: {node: '>=20.0.0'} peerDependencies: - react: '>=15' + react: '>=18' + react-dom: '>=18' - react-router@5.3.4: - resolution: {integrity: sha512-Ys9K+ppnJah3QuaRiLxk+jDWOR1MekYQrlytiXxC1RyfbdsZkS5pvKAzCCr031xHixZwpnsYNT5xysdFHQaYsA==} + react-router@7.18.2: + resolution: {integrity: sha512-aUVMjFm3GAPTTZL7oYr5E7ETiqfQCHRLH+B+5afnICvf0r7kkK4eR6SMuwbSTJw/7t+12khT/Kahij49fqOCIg==} + engines: {node: '>=20.0.0'} peerDependencies: - react: '>=15' + react: '>=18' + react-dom: '>=18' + peerDependenciesMeta: + react-dom: + optional: true react-scripts@5.0.1: resolution: {integrity: sha512-8VAmEm/ZAwQzJ+GOMLbBsTdDKOpuZh7RPs0UymvBR2vRk4iZWCskjbFnxqjrzoIvlNNRZ3QJFx6/qDSi6zSnaQ==} @@ -5228,19 +5218,14 @@ packages: peerDependencies: react: ^16.0.0 || ^17.0.0 || ^18.0.0 - react-test-renderer@17.0.2: - resolution: {integrity: sha512-yaQ9cB89c17PUb0x6UfWRs7kQCorVdHlutU1boVPEsB8IDZH6n9tHxMacc3y0JoXOJUsZb/t/Mb8FUWMKaM7iQ==} - peerDependencies: - react: 17.0.2 - react-transition-group@3.0.0: resolution: {integrity: sha512-A9ojB/LWECbFj58SNfjK1X9aaAU+1olLS0DFSikvrr2KfMaiBELemHDa5dKNvcTk2t3gUtDL/PJpFrBKDfMpLg==} peerDependencies: react: '>=16.6.0' react-dom: '>=16.6.0' - react@17.0.2: - resolution: {integrity: sha512-gnhPt75i/dq/z3/6q/0asP78D0u592D5L1pd7M8P+dck6Fu/jJeL6iVVK23fptSUZj8Vjf++7wXA8UNclGQcbA==} + react@18.3.1: + resolution: {integrity: sha512-wS+hAgJShR0KhEvPJArfuPVN1+Hz1t0Y6n5jLrGQbkb4urgPE/0Rve+1kMB1v/oWgHgm4WIcV+i7F2pTVj+2iQ==} engines: {node: '>=0.10.0'} reactstrap@8.10.1: @@ -5333,9 +5318,6 @@ packages: resolution: {integrity: sha512-qYg9KP24dD5qka9J47d0aVky0N+b4fTU89LN9iDnjB5waksiC49rvMB0PrUJQGoTmH50XPiqOvAjDfaijGxYZw==} engines: {node: '>=8'} - resolve-pathname@3.0.0: - resolution: {integrity: sha512-C7rARubxI8bXFNB/hqcp/4iUeIXJhJZvFPFPiSPRnhU5UPxzMFIl+2E6yY6c4k9giDJAhtV+enfA+G89N6Csng==} - resolve-url-loader@4.0.0: resolution: {integrity: sha512-05VEMczVREcbtT7Bz+C+96eUO5HDNvdthIiMB34t7FcF8ehcu4wC0sSgPUubs3XW2Q3CNLJk/BJrCU9wVRymiA==} engines: {node: '>=8.9'} @@ -5459,8 +5441,8 @@ packages: resolution: {integrity: sha512-5LBh1Tls8c9xgGjw3QrMwETmTMVk0oFgvrFSvWx62llR2hcEInrKNZ2GZCCuuy2lvWrdl5jhbpeqc5hRYKFOcw==} engines: {node: '>=10'} - scheduler@0.20.2: - resolution: {integrity: sha512-2eWfGgAqqWFGqtdMmcL5zCMK1U8KlXv8SQFGglL3CEtd0aDVDWgeF/YoCmvln55m5zSk3J/20hTaSBeSObsQDQ==} + scheduler@0.23.2: + resolution: {integrity: sha512-UOShsPwz7NrMUqhR6t0hWjFduvOzbtv7toDH1/hIrfRNIDBnnBWd0CwJTGvTpngVlmwGCdP9/Zl/tVrDqcuYzQ==} schema-utils@2.7.0: resolution: {integrity: sha512-0ilKFI6QQF5nxDZLFn2dMjvc4hjg/Wkg7rHd3jK6/A4a1Hl9VFdQWvgB1UMGoU94pad1P/8N7fMcEnLnSiju8A==} @@ -5516,6 +5498,9 @@ packages: resolution: {integrity: sha512-x0RTqQel6g5SY7Lg6ZreMmsOzncHFU7nhnRWkKgWuMTu5NN0DR5oruckMqRvacAN9d5w6ARnRBXl9xhDCgfMeA==} engines: {node: '>= 0.8.0'} + set-cookie-parser@2.7.2: + resolution: {integrity: sha512-oeM1lpU/UvhTxw+g3cIfxXHyJRc/uidd3yK1P242gzHds0udQBYzs3y8j4gCCW+ZJ7ad0yctld8RYO+bdurlvw==} + set-function-length@1.2.2: resolution: {integrity: sha512-pgRc4hJ4/sNjWCSS9AmnS40x3bNMDTknHgL5UaMBTMyJnU90EgWh1Rz+MC9eFu4BuN/UwZjKQuY/1v3rM7HMfg==} engines: {node: '>= 0.4'} @@ -5899,12 +5884,6 @@ packages: thunky@1.1.0: resolution: {integrity: sha512-eHY7nBftgThBqOyHGVN+l8gF0BucP09fMo0oO/Lb0w1OF80dJv+lDVpXG60WMQvkcxAkNybKsrEIE3ZtKGmPrA==} - tiny-invariant@1.3.3: - resolution: {integrity: sha512-+FbBPE1o9QAYvviau/qC5SE3caw21q3xkvWKBtja5vgqOWIHHJ3ioaq1VPfn/Szqctz2bU/oYeKd9/z5BL+PVg==} - - tiny-warning@1.0.3: - resolution: {integrity: sha512-lBN9zLN/oAf68o3zNXYrdCt1kP8WsiGW8Oo2ka41b2IM5JL/S1CTyX1rW0mb/zSuJun0ZUrDxx4sqvYS2FWzPA==} - tinyglobby@0.2.16: resolution: {integrity: sha512-pn99VhoACYR8nFHhxqix+uvsbXineAasWm5ojXoN8xEwK5Kd3/TrhNn1wByuD52UxWRLy8pu+kRMniEi6Eq9Zg==} engines: {node: '>=12.0.0'} @@ -5943,33 +5922,6 @@ packages: ts-interface-checker@0.1.13: resolution: {integrity: sha512-Y/arvbn+rrz3JCKl9C4kVNfTfSm2/mEp5FSz5EsZSANGPSlQrpRI5M4PKF+mJnE52jOO90PnPSc3Ur3bTQw0gA==} - ts-jest@29.4.12: - resolution: {integrity: sha512-Ov6ClY53Fflh6BGAnY2DlTq1hYDrTycz2PVTXBWFW2CU+9zrEqAp9fWdGXl42EXO5RLSFAcAZ2JFKbP+zBTFfw==} - engines: {node: ^14.15.0 || ^16.10.0 || ^18.0.0 || >=20.0.0} - hasBin: true - peerDependencies: - '@babel/core': '>=7.0.0-beta.0 <8' - '@jest/transform': ^29.0.0 || ^30.0.0 - '@jest/types': ^29.0.0 || ^30.0.0 - babel-jest: ^29.0.0 || ^30.0.0 - esbuild: '*' - jest: ^29.0.0 || ^30.0.0 - jest-util: ^29.0.0 || ^30.0.0 - typescript: '>=4.3 <7' - peerDependenciesMeta: - '@babel/core': - optional: true - '@jest/transform': - optional: true - '@jest/types': - optional: true - babel-jest: - optional: true - esbuild: - optional: true - jest-util: - optional: true - tsconfig-paths@3.15.0: resolution: {integrity: sha512-2Ac2RgzDe/cn48GvOe3M+o82pEFewD3UPbyoUHHdKasHwJKjds4fLXWf/Ux5kATBKN20oaFGu+jbElp1pos0mg==} @@ -6059,10 +6011,6 @@ packages: undici-types@6.21.0: resolution: {integrity: sha512-iwDZqg0QAGrg9Rav5H4n0M64c3mkR59cJ6wQp+7C4nI0gsmExaedaYLNO44eT4AtBBwjbTiGPMlt2Md0T9H9JQ==} - undici@7.25.0: - resolution: {integrity: sha512-xXnp4kTyor2Zq+J1FfPI6Eq3ew5h6Vl0F/8d9XU5zZQf1tX9s2Su1/3PiMmUANFULpmksxkClamIZcaUqryHsQ==} - engines: {node: '>=20.18.1'} - unicode-canonical-property-names-ecmascript@2.0.1: resolution: {integrity: sha512-dA8WbNeb2a6oQzAQ55YlT5vQAWGV9WXOsi3SskE3bcCdM0P4SDd+24zS/OCacdRq5BkdsRj9q3Pg6YyQoxIGqg==} engines: {node: '>=4'} @@ -6136,9 +6084,6 @@ packages: resolution: {integrity: sha512-FGtKtv3xIpR6BYhvgH8MI/y78oT7d8Au3ww4QIxymrCtZEh5b8gCw2siywE+puhEmuWKDtmfrvF5UlB298ut3w==} engines: {node: '>=10.12.0'} - value-equal@1.0.1: - resolution: {integrity: sha512-NOJ6JZCAWr0zlxZt+xqCHNTEKOsrks2HQd4MqhP1qy4z1SkbEP467eNx6TgDKXMvUOb+OENfJCZwM+16n7fRfw==} - vary@1.1.2: resolution: {integrity: sha512-BNGbWLfd0eUPabhkXUVm0j8uuvREyTh5ovRa/dyow/BqAbZJyC+5fU+IzQOzmAKzYqYRAISoRhdQr3eIZ/PXqg==} engines: {node: '>= 0.8'} @@ -6243,21 +6188,12 @@ packages: resolution: {integrity: sha512-b5lim54JOPN9HtzvK9HFXvBma/rnfFeqsic0hSpjtDbVxR3dJKLc+KB4V6GgiGOvl7CY/KNh8rxSo9DKQrnUEw==} deprecated: Use @exodus/bytes instead for a more spec-conformant and faster implementation - whatwg-encoding@3.1.1: - resolution: {integrity: sha512-6qN4hJdMwfYBtE3YBTTHhoeuUrDBPZmbQaxWAqSALV/MeEnR5z1xd8UKud2RAkFoPkmB+hli1TZSnyi84xz1vQ==} - engines: {node: '>=18'} - deprecated: Use @exodus/bytes instead for a more spec-conformant and faster implementation - whatwg-fetch@3.6.20: resolution: {integrity: sha512-EqhiFU6daOA8kpjOWTL0olhVOF3i7OrFzSYiGsEMB8GcXS+RrzauAERX65xMeNWVqxA6HXH2m69Z9LaKKdisfg==} whatwg-mimetype@2.3.0: resolution: {integrity: sha512-M4yMwr6mAnQz76TbJm914+gPpB/nCwvZbJU28cUD6dR004SAxDLOOSUaB1JDRqLtaOV/vi0IC5lEAGFgrjGv/g==} - whatwg-mimetype@4.0.0: - resolution: {integrity: sha512-QaKxh0eNIi2mE9p2vEdzfagOKHCcj1pJ56EEHGQOVxp8r9/iszLUUV7v89x9O1p/T+NlTM5W7jW6+cz4Fq1YVg==} - engines: {node: '>=18'} - whatwg-url@5.0.0: resolution: {integrity: sha512-saE57nupxk6v3HY35+jzBwYa0rKSy0XR8JSxZPwgLr7ys0IBzhGviA1/TUGJLmSVqs8pb9AnvICXEuOHLprYTw==} @@ -6297,9 +6233,6 @@ packages: resolution: {integrity: sha512-BN22B5eaMMI9UMtjrGd5g5eCYPpCPDUy0FJXbYsaT5zYxjFOckS53SQDE3pWkVoWpHXVb3BrYcEN4Twa55B5cA==} engines: {node: '>=0.10.0'} - wordwrap@1.0.0: - resolution: {integrity: sha512-gvVzJFlPycKc5dZN4yPkP8w7Dc37BtP1yczEneOb4uq34pXZcvrtRTmWV8W+Ume+XCxKgbjM+nevkyFPMybd4Q==} - workbox-background-sync@6.6.0: resolution: {integrity: sha512-jkf4ZdgOJxC9u2vztxLuPT/UjlH7m/nWRQ/MgGL0v8BJHoZdVGJd18Kck+a0e55wGXdqyHO+4IQTk0685g4MUw==} @@ -6412,10 +6345,6 @@ packages: resolution: {integrity: sha512-y11nGElTIV+CT3Zv9t7VKl+Q3hTQoT9a1Qzezhhl6Rp21gJ/IVTW7Z3y9EWXhuUBC2Shnf+DX0antecpAwSP8w==} engines: {node: '>=10'} - yargs-parser@21.1.1: - resolution: {integrity: sha512-tVpsJW7DdjecAiFpbIB1e3qxIQsE6NoPc5/eTdrbbIC4h0LVsWhnoa3g+m2HclBIujHzsxZ4VJVA+GUuc2/LBw==} - engines: {node: '>=12'} - yargs@16.2.0: resolution: {integrity: sha512-D1mvvtDG0L5ft/jGWkLpG1+m0eQxOfaBvTNELraWj22wSVUMWxZUvYgJYcKh6jGGIkJFhH4IZPQhR4TKpc8mBw==} engines: {node: '>=10'} @@ -6442,31 +6371,31 @@ snapshots: '@babel/compat-data@7.29.7': {} - '@babel/core@7.29.7': + '@babel/core@7.29.7(supports-color@8.1.1)': dependencies: '@babel/code-frame': 7.29.7 '@babel/generator': 7.29.7 '@babel/helper-compilation-targets': 7.29.7 - '@babel/helper-module-transforms': 7.29.7(@babel/core@7.29.7) + '@babel/helper-module-transforms': 7.29.7(@babel/core@7.29.7(supports-color@8.1.1))(supports-color@8.1.1) '@babel/helpers': 7.29.7 '@babel/parser': 7.29.7 '@babel/template': 7.29.7 - '@babel/traverse': 7.29.7 + '@babel/traverse': 7.29.7(supports-color@8.1.1) '@babel/types': 7.29.7 '@jridgewell/remapping': 2.3.5 convert-source-map: 2.0.0 - debug: 4.4.3 + debug: 4.4.3(supports-color@8.1.1) gensync: 1.0.0-beta.2 json5: 2.2.3 semver: 6.3.1 transitivePeerDependencies: - supports-color - '@babel/eslint-parser@7.29.7(@babel/core@7.29.7)(eslint@8.57.1)': + '@babel/eslint-parser@7.29.7(@babel/core@7.29.7(supports-color@8.1.1))(eslint@8.57.1(supports-color@8.1.1))': dependencies: - '@babel/core': 7.29.7 + '@babel/core': 7.29.7(supports-color@8.1.1) '@nicolo-ribaudo/eslint-scope-5-internals': 5.1.1-v1 - eslint: 8.57.1 + eslint: 8.57.1(supports-color@8.1.1) eslint-visitor-keys: 2.1.0 semver: 6.3.1 @@ -6490,32 +6419,32 @@ snapshots: lru-cache: 5.1.1 semver: 6.3.1 - '@babel/helper-create-class-features-plugin@7.29.7(@babel/core@7.29.7)': + '@babel/helper-create-class-features-plugin@7.29.7(@babel/core@7.29.7(supports-color@8.1.1))(supports-color@8.1.1)': dependencies: - '@babel/core': 7.29.7 + '@babel/core': 7.29.7(supports-color@8.1.1) '@babel/helper-annotate-as-pure': 7.29.7 - '@babel/helper-member-expression-to-functions': 7.29.7 + '@babel/helper-member-expression-to-functions': 7.29.7(supports-color@8.1.1) '@babel/helper-optimise-call-expression': 7.29.7 - '@babel/helper-replace-supers': 7.29.7(@babel/core@7.29.7) - '@babel/helper-skip-transparent-expression-wrappers': 7.29.7 - '@babel/traverse': 7.29.7 + '@babel/helper-replace-supers': 7.29.7(@babel/core@7.29.7(supports-color@8.1.1))(supports-color@8.1.1) + '@babel/helper-skip-transparent-expression-wrappers': 7.29.7(supports-color@8.1.1) + '@babel/traverse': 7.29.7(supports-color@8.1.1) semver: 6.3.1 transitivePeerDependencies: - supports-color - '@babel/helper-create-regexp-features-plugin@7.29.7(@babel/core@7.29.7)': + '@babel/helper-create-regexp-features-plugin@7.29.7(@babel/core@7.29.7(supports-color@8.1.1))': dependencies: - '@babel/core': 7.29.7 + '@babel/core': 7.29.7(supports-color@8.1.1) '@babel/helper-annotate-as-pure': 7.29.7 regexpu-core: 6.4.0 semver: 6.3.1 - '@babel/helper-define-polyfill-provider@0.6.8(@babel/core@7.29.7)': + '@babel/helper-define-polyfill-provider@0.6.8(@babel/core@7.29.7(supports-color@8.1.1))(supports-color@8.1.1)': dependencies: - '@babel/core': 7.29.7 + '@babel/core': 7.29.7(supports-color@8.1.1) '@babel/helper-compilation-targets': 7.29.7 '@babel/helper-plugin-utils': 7.29.7 - debug: 4.4.3 + debug: 4.4.3(supports-color@8.1.1) lodash.debounce: 4.0.8 resolve: 1.22.12 transitivePeerDependencies: @@ -6523,26 +6452,26 @@ snapshots: '@babel/helper-globals@7.29.7': {} - '@babel/helper-member-expression-to-functions@7.29.7': + '@babel/helper-member-expression-to-functions@7.29.7(supports-color@8.1.1)': dependencies: - '@babel/traverse': 7.29.7 + '@babel/traverse': 7.29.7(supports-color@8.1.1) '@babel/types': 7.29.7 transitivePeerDependencies: - supports-color - '@babel/helper-module-imports@7.29.7': + '@babel/helper-module-imports@7.29.7(supports-color@8.1.1)': dependencies: - '@babel/traverse': 7.29.7 + '@babel/traverse': 7.29.7(supports-color@8.1.1) '@babel/types': 7.29.7 transitivePeerDependencies: - supports-color - '@babel/helper-module-transforms@7.29.7(@babel/core@7.29.7)': + '@babel/helper-module-transforms@7.29.7(@babel/core@7.29.7(supports-color@8.1.1))(supports-color@8.1.1)': dependencies: - '@babel/core': 7.29.7 - '@babel/helper-module-imports': 7.29.7 + '@babel/core': 7.29.7(supports-color@8.1.1) + '@babel/helper-module-imports': 7.29.7(supports-color@8.1.1) '@babel/helper-validator-identifier': 7.29.7 - '@babel/traverse': 7.29.7 + '@babel/traverse': 7.29.7(supports-color@8.1.1) transitivePeerDependencies: - supports-color @@ -6552,27 +6481,27 @@ snapshots: '@babel/helper-plugin-utils@7.29.7': {} - '@babel/helper-remap-async-to-generator@7.29.7(@babel/core@7.29.7)': + '@babel/helper-remap-async-to-generator@7.29.7(@babel/core@7.29.7(supports-color@8.1.1))(supports-color@8.1.1)': dependencies: - '@babel/core': 7.29.7 + '@babel/core': 7.29.7(supports-color@8.1.1) '@babel/helper-annotate-as-pure': 7.29.7 - '@babel/helper-wrap-function': 7.29.7 - '@babel/traverse': 7.29.7 + '@babel/helper-wrap-function': 7.29.7(supports-color@8.1.1) + '@babel/traverse': 7.29.7(supports-color@8.1.1) transitivePeerDependencies: - supports-color - '@babel/helper-replace-supers@7.29.7(@babel/core@7.29.7)': + '@babel/helper-replace-supers@7.29.7(@babel/core@7.29.7(supports-color@8.1.1))(supports-color@8.1.1)': dependencies: - '@babel/core': 7.29.7 - '@babel/helper-member-expression-to-functions': 7.29.7 + '@babel/core': 7.29.7(supports-color@8.1.1) + '@babel/helper-member-expression-to-functions': 7.29.7(supports-color@8.1.1) '@babel/helper-optimise-call-expression': 7.29.7 - '@babel/traverse': 7.29.7 + '@babel/traverse': 7.29.7(supports-color@8.1.1) transitivePeerDependencies: - supports-color - '@babel/helper-skip-transparent-expression-wrappers@7.29.7': + '@babel/helper-skip-transparent-expression-wrappers@7.29.7(supports-color@8.1.1)': dependencies: - '@babel/traverse': 7.29.7 + '@babel/traverse': 7.29.7(supports-color@8.1.1) '@babel/types': 7.29.7 transitivePeerDependencies: - supports-color @@ -6583,10 +6512,10 @@ snapshots: '@babel/helper-validator-option@7.29.7': {} - '@babel/helper-wrap-function@7.29.7': + '@babel/helper-wrap-function@7.29.7(supports-color@8.1.1)': dependencies: '@babel/template': 7.29.7 - '@babel/traverse': 7.29.7 + '@babel/traverse': 7.29.7(supports-color@8.1.1) '@babel/types': 7.29.7 transitivePeerDependencies: - supports-color @@ -6600,715 +6529,715 @@ snapshots: dependencies: '@babel/types': 7.29.7 - '@babel/plugin-bugfix-firefox-class-in-computed-class-key@7.29.7(@babel/core@7.29.7)': + '@babel/plugin-bugfix-firefox-class-in-computed-class-key@7.29.7(@babel/core@7.29.7(supports-color@8.1.1))(supports-color@8.1.1)': dependencies: - '@babel/core': 7.29.7 + '@babel/core': 7.29.7(supports-color@8.1.1) '@babel/helper-plugin-utils': 7.29.7 - '@babel/traverse': 7.29.7 + '@babel/traverse': 7.29.7(supports-color@8.1.1) transitivePeerDependencies: - supports-color - '@babel/plugin-bugfix-safari-class-field-initializer-scope@7.29.7(@babel/core@7.29.7)': + '@babel/plugin-bugfix-safari-class-field-initializer-scope@7.29.7(@babel/core@7.29.7(supports-color@8.1.1))': dependencies: - '@babel/core': 7.29.7 + '@babel/core': 7.29.7(supports-color@8.1.1) '@babel/helper-plugin-utils': 7.29.7 - '@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression@7.29.7(@babel/core@7.29.7)': + '@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression@7.29.7(@babel/core@7.29.7(supports-color@8.1.1))': dependencies: - '@babel/core': 7.29.7 + '@babel/core': 7.29.7(supports-color@8.1.1) '@babel/helper-plugin-utils': 7.29.7 - '@babel/plugin-bugfix-safari-rest-destructuring-rhs-array@7.29.7(@babel/core@7.29.7)': + '@babel/plugin-bugfix-safari-rest-destructuring-rhs-array@7.29.7(@babel/core@7.29.7(supports-color@8.1.1))(supports-color@8.1.1)': dependencies: - '@babel/core': 7.29.7 + '@babel/core': 7.29.7(supports-color@8.1.1) '@babel/helper-plugin-utils': 7.29.7 - '@babel/helper-skip-transparent-expression-wrappers': 7.29.7 + '@babel/helper-skip-transparent-expression-wrappers': 7.29.7(supports-color@8.1.1) transitivePeerDependencies: - supports-color - '@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining@7.29.7(@babel/core@7.29.7)': + '@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining@7.29.7(@babel/core@7.29.7(supports-color@8.1.1))(supports-color@8.1.1)': dependencies: - '@babel/core': 7.29.7 + '@babel/core': 7.29.7(supports-color@8.1.1) '@babel/helper-plugin-utils': 7.29.7 - '@babel/helper-skip-transparent-expression-wrappers': 7.29.7 - '@babel/plugin-transform-optional-chaining': 7.29.7(@babel/core@7.29.7) + '@babel/helper-skip-transparent-expression-wrappers': 7.29.7(supports-color@8.1.1) + '@babel/plugin-transform-optional-chaining': 7.29.7(@babel/core@7.29.7(supports-color@8.1.1))(supports-color@8.1.1) transitivePeerDependencies: - supports-color - '@babel/plugin-bugfix-v8-static-class-fields-redefine-readonly@7.29.7(@babel/core@7.29.7)': + '@babel/plugin-bugfix-v8-static-class-fields-redefine-readonly@7.29.7(@babel/core@7.29.7(supports-color@8.1.1))(supports-color@8.1.1)': dependencies: - '@babel/core': 7.29.7 + '@babel/core': 7.29.7(supports-color@8.1.1) '@babel/helper-plugin-utils': 7.29.7 - '@babel/traverse': 7.29.7 + '@babel/traverse': 7.29.7(supports-color@8.1.1) transitivePeerDependencies: - supports-color - '@babel/plugin-proposal-class-properties@7.18.6(@babel/core@7.29.7)': + '@babel/plugin-proposal-class-properties@7.18.6(@babel/core@7.29.7(supports-color@8.1.1))(supports-color@8.1.1)': dependencies: - '@babel/core': 7.29.7 - '@babel/helper-create-class-features-plugin': 7.29.7(@babel/core@7.29.7) + '@babel/core': 7.29.7(supports-color@8.1.1) + '@babel/helper-create-class-features-plugin': 7.29.7(@babel/core@7.29.7(supports-color@8.1.1))(supports-color@8.1.1) '@babel/helper-plugin-utils': 7.29.7 transitivePeerDependencies: - supports-color - '@babel/plugin-proposal-decorators@7.29.7(@babel/core@7.29.7)': + '@babel/plugin-proposal-decorators@7.29.7(@babel/core@7.29.7(supports-color@8.1.1))(supports-color@8.1.1)': dependencies: - '@babel/core': 7.29.7 - '@babel/helper-create-class-features-plugin': 7.29.7(@babel/core@7.29.7) + '@babel/core': 7.29.7(supports-color@8.1.1) + '@babel/helper-create-class-features-plugin': 7.29.7(@babel/core@7.29.7(supports-color@8.1.1))(supports-color@8.1.1) '@babel/helper-plugin-utils': 7.29.7 - '@babel/plugin-syntax-decorators': 7.29.7(@babel/core@7.29.7) + '@babel/plugin-syntax-decorators': 7.29.7(@babel/core@7.29.7(supports-color@8.1.1)) transitivePeerDependencies: - supports-color - '@babel/plugin-proposal-nullish-coalescing-operator@7.18.6(@babel/core@7.29.7)': + '@babel/plugin-proposal-nullish-coalescing-operator@7.18.6(@babel/core@7.29.7(supports-color@8.1.1))': dependencies: - '@babel/core': 7.29.7 + '@babel/core': 7.29.7(supports-color@8.1.1) '@babel/helper-plugin-utils': 7.29.7 - '@babel/plugin-syntax-nullish-coalescing-operator': 7.8.3(@babel/core@7.29.7) + '@babel/plugin-syntax-nullish-coalescing-operator': 7.8.3(@babel/core@7.29.7(supports-color@8.1.1)) - '@babel/plugin-proposal-numeric-separator@7.18.6(@babel/core@7.29.7)': + '@babel/plugin-proposal-numeric-separator@7.18.6(@babel/core@7.29.7(supports-color@8.1.1))': dependencies: - '@babel/core': 7.29.7 + '@babel/core': 7.29.7(supports-color@8.1.1) '@babel/helper-plugin-utils': 7.29.7 - '@babel/plugin-syntax-numeric-separator': 7.10.4(@babel/core@7.29.7) + '@babel/plugin-syntax-numeric-separator': 7.10.4(@babel/core@7.29.7(supports-color@8.1.1)) - '@babel/plugin-proposal-optional-chaining@7.21.0(@babel/core@7.29.7)': + '@babel/plugin-proposal-optional-chaining@7.21.0(@babel/core@7.29.7(supports-color@8.1.1))(supports-color@8.1.1)': dependencies: - '@babel/core': 7.29.7 + '@babel/core': 7.29.7(supports-color@8.1.1) '@babel/helper-plugin-utils': 7.29.7 - '@babel/helper-skip-transparent-expression-wrappers': 7.29.7 - '@babel/plugin-syntax-optional-chaining': 7.8.3(@babel/core@7.29.7) + '@babel/helper-skip-transparent-expression-wrappers': 7.29.7(supports-color@8.1.1) + '@babel/plugin-syntax-optional-chaining': 7.8.3(@babel/core@7.29.7(supports-color@8.1.1)) transitivePeerDependencies: - supports-color - '@babel/plugin-proposal-private-methods@7.18.6(@babel/core@7.29.7)': + '@babel/plugin-proposal-private-methods@7.18.6(@babel/core@7.29.7(supports-color@8.1.1))(supports-color@8.1.1)': dependencies: - '@babel/core': 7.29.7 - '@babel/helper-create-class-features-plugin': 7.29.7(@babel/core@7.29.7) + '@babel/core': 7.29.7(supports-color@8.1.1) + '@babel/helper-create-class-features-plugin': 7.29.7(@babel/core@7.29.7(supports-color@8.1.1))(supports-color@8.1.1) '@babel/helper-plugin-utils': 7.29.7 transitivePeerDependencies: - supports-color - '@babel/plugin-proposal-private-property-in-object@7.21.0-placeholder-for-preset-env.2(@babel/core@7.29.7)': + '@babel/plugin-proposal-private-property-in-object@7.21.0-placeholder-for-preset-env.2(@babel/core@7.29.7(supports-color@8.1.1))': dependencies: - '@babel/core': 7.29.7 + '@babel/core': 7.29.7(supports-color@8.1.1) - '@babel/plugin-proposal-private-property-in-object@7.21.11(@babel/core@7.29.7)': + '@babel/plugin-proposal-private-property-in-object@7.21.11(@babel/core@7.29.7(supports-color@8.1.1))(supports-color@8.1.1)': dependencies: - '@babel/core': 7.29.7 + '@babel/core': 7.29.7(supports-color@8.1.1) '@babel/helper-annotate-as-pure': 7.29.7 - '@babel/helper-create-class-features-plugin': 7.29.7(@babel/core@7.29.7) + '@babel/helper-create-class-features-plugin': 7.29.7(@babel/core@7.29.7(supports-color@8.1.1))(supports-color@8.1.1) '@babel/helper-plugin-utils': 7.29.7 - '@babel/plugin-syntax-private-property-in-object': 7.14.5(@babel/core@7.29.7) + '@babel/plugin-syntax-private-property-in-object': 7.14.5(@babel/core@7.29.7(supports-color@8.1.1)) transitivePeerDependencies: - supports-color - '@babel/plugin-syntax-async-generators@7.8.4(@babel/core@7.29.7)': + '@babel/plugin-syntax-async-generators@7.8.4(@babel/core@7.29.7(supports-color@8.1.1))': dependencies: - '@babel/core': 7.29.7 + '@babel/core': 7.29.7(supports-color@8.1.1) '@babel/helper-plugin-utils': 7.29.7 - '@babel/plugin-syntax-bigint@7.8.3(@babel/core@7.29.7)': + '@babel/plugin-syntax-bigint@7.8.3(@babel/core@7.29.7(supports-color@8.1.1))': dependencies: - '@babel/core': 7.29.7 + '@babel/core': 7.29.7(supports-color@8.1.1) '@babel/helper-plugin-utils': 7.29.7 - '@babel/plugin-syntax-class-properties@7.12.13(@babel/core@7.29.7)': + '@babel/plugin-syntax-class-properties@7.12.13(@babel/core@7.29.7(supports-color@8.1.1))': dependencies: - '@babel/core': 7.29.7 + '@babel/core': 7.29.7(supports-color@8.1.1) '@babel/helper-plugin-utils': 7.29.7 - '@babel/plugin-syntax-class-static-block@7.14.5(@babel/core@7.29.7)': + '@babel/plugin-syntax-class-static-block@7.14.5(@babel/core@7.29.7(supports-color@8.1.1))': dependencies: - '@babel/core': 7.29.7 + '@babel/core': 7.29.7(supports-color@8.1.1) '@babel/helper-plugin-utils': 7.29.7 - '@babel/plugin-syntax-decorators@7.29.7(@babel/core@7.29.7)': + '@babel/plugin-syntax-decorators@7.29.7(@babel/core@7.29.7(supports-color@8.1.1))': dependencies: - '@babel/core': 7.29.7 + '@babel/core': 7.29.7(supports-color@8.1.1) '@babel/helper-plugin-utils': 7.29.7 - '@babel/plugin-syntax-flow@7.29.7(@babel/core@7.29.7)': + '@babel/plugin-syntax-flow@7.29.7(@babel/core@7.29.7(supports-color@8.1.1))': dependencies: - '@babel/core': 7.29.7 + '@babel/core': 7.29.7(supports-color@8.1.1) '@babel/helper-plugin-utils': 7.29.7 - '@babel/plugin-syntax-import-assertions@7.29.7(@babel/core@7.29.7)': + '@babel/plugin-syntax-import-assertions@7.29.7(@babel/core@7.29.7(supports-color@8.1.1))': dependencies: - '@babel/core': 7.29.7 + '@babel/core': 7.29.7(supports-color@8.1.1) '@babel/helper-plugin-utils': 7.29.7 - '@babel/plugin-syntax-import-attributes@7.29.7(@babel/core@7.29.7)': + '@babel/plugin-syntax-import-attributes@7.29.7(@babel/core@7.29.7(supports-color@8.1.1))': dependencies: - '@babel/core': 7.29.7 + '@babel/core': 7.29.7(supports-color@8.1.1) '@babel/helper-plugin-utils': 7.29.7 - '@babel/plugin-syntax-import-meta@7.10.4(@babel/core@7.29.7)': + '@babel/plugin-syntax-import-meta@7.10.4(@babel/core@7.29.7(supports-color@8.1.1))': dependencies: - '@babel/core': 7.29.7 + '@babel/core': 7.29.7(supports-color@8.1.1) '@babel/helper-plugin-utils': 7.29.7 - '@babel/plugin-syntax-json-strings@7.8.3(@babel/core@7.29.7)': + '@babel/plugin-syntax-json-strings@7.8.3(@babel/core@7.29.7(supports-color@8.1.1))': dependencies: - '@babel/core': 7.29.7 + '@babel/core': 7.29.7(supports-color@8.1.1) '@babel/helper-plugin-utils': 7.29.7 - '@babel/plugin-syntax-jsx@7.29.7(@babel/core@7.29.7)': + '@babel/plugin-syntax-jsx@7.29.7(@babel/core@7.29.7(supports-color@8.1.1))': dependencies: - '@babel/core': 7.29.7 + '@babel/core': 7.29.7(supports-color@8.1.1) '@babel/helper-plugin-utils': 7.29.7 - '@babel/plugin-syntax-logical-assignment-operators@7.10.4(@babel/core@7.29.7)': + '@babel/plugin-syntax-logical-assignment-operators@7.10.4(@babel/core@7.29.7(supports-color@8.1.1))': dependencies: - '@babel/core': 7.29.7 + '@babel/core': 7.29.7(supports-color@8.1.1) '@babel/helper-plugin-utils': 7.29.7 - '@babel/plugin-syntax-nullish-coalescing-operator@7.8.3(@babel/core@7.29.7)': + '@babel/plugin-syntax-nullish-coalescing-operator@7.8.3(@babel/core@7.29.7(supports-color@8.1.1))': dependencies: - '@babel/core': 7.29.7 + '@babel/core': 7.29.7(supports-color@8.1.1) '@babel/helper-plugin-utils': 7.29.7 - '@babel/plugin-syntax-numeric-separator@7.10.4(@babel/core@7.29.7)': + '@babel/plugin-syntax-numeric-separator@7.10.4(@babel/core@7.29.7(supports-color@8.1.1))': dependencies: - '@babel/core': 7.29.7 + '@babel/core': 7.29.7(supports-color@8.1.1) '@babel/helper-plugin-utils': 7.29.7 - '@babel/plugin-syntax-object-rest-spread@7.8.3(@babel/core@7.29.7)': + '@babel/plugin-syntax-object-rest-spread@7.8.3(@babel/core@7.29.7(supports-color@8.1.1))': dependencies: - '@babel/core': 7.29.7 + '@babel/core': 7.29.7(supports-color@8.1.1) '@babel/helper-plugin-utils': 7.29.7 - '@babel/plugin-syntax-optional-catch-binding@7.8.3(@babel/core@7.29.7)': + '@babel/plugin-syntax-optional-catch-binding@7.8.3(@babel/core@7.29.7(supports-color@8.1.1))': dependencies: - '@babel/core': 7.29.7 + '@babel/core': 7.29.7(supports-color@8.1.1) '@babel/helper-plugin-utils': 7.29.7 - '@babel/plugin-syntax-optional-chaining@7.8.3(@babel/core@7.29.7)': + '@babel/plugin-syntax-optional-chaining@7.8.3(@babel/core@7.29.7(supports-color@8.1.1))': dependencies: - '@babel/core': 7.29.7 + '@babel/core': 7.29.7(supports-color@8.1.1) '@babel/helper-plugin-utils': 7.29.7 - '@babel/plugin-syntax-private-property-in-object@7.14.5(@babel/core@7.29.7)': + '@babel/plugin-syntax-private-property-in-object@7.14.5(@babel/core@7.29.7(supports-color@8.1.1))': dependencies: - '@babel/core': 7.29.7 + '@babel/core': 7.29.7(supports-color@8.1.1) '@babel/helper-plugin-utils': 7.29.7 - '@babel/plugin-syntax-top-level-await@7.14.5(@babel/core@7.29.7)': + '@babel/plugin-syntax-top-level-await@7.14.5(@babel/core@7.29.7(supports-color@8.1.1))': dependencies: - '@babel/core': 7.29.7 + '@babel/core': 7.29.7(supports-color@8.1.1) '@babel/helper-plugin-utils': 7.29.7 - '@babel/plugin-syntax-typescript@7.29.7(@babel/core@7.29.7)': + '@babel/plugin-syntax-typescript@7.29.7(@babel/core@7.29.7(supports-color@8.1.1))': dependencies: - '@babel/core': 7.29.7 + '@babel/core': 7.29.7(supports-color@8.1.1) '@babel/helper-plugin-utils': 7.29.7 - '@babel/plugin-syntax-unicode-sets-regex@7.18.6(@babel/core@7.29.7)': + '@babel/plugin-syntax-unicode-sets-regex@7.18.6(@babel/core@7.29.7(supports-color@8.1.1))': dependencies: - '@babel/core': 7.29.7 - '@babel/helper-create-regexp-features-plugin': 7.29.7(@babel/core@7.29.7) + '@babel/core': 7.29.7(supports-color@8.1.1) + '@babel/helper-create-regexp-features-plugin': 7.29.7(@babel/core@7.29.7(supports-color@8.1.1)) '@babel/helper-plugin-utils': 7.29.7 - '@babel/plugin-transform-arrow-functions@7.29.7(@babel/core@7.29.7)': + '@babel/plugin-transform-arrow-functions@7.29.7(@babel/core@7.29.7(supports-color@8.1.1))': dependencies: - '@babel/core': 7.29.7 + '@babel/core': 7.29.7(supports-color@8.1.1) '@babel/helper-plugin-utils': 7.29.7 - '@babel/plugin-transform-async-generator-functions@7.29.7(@babel/core@7.29.7)': + '@babel/plugin-transform-async-generator-functions@7.29.7(@babel/core@7.29.7(supports-color@8.1.1))(supports-color@8.1.1)': dependencies: - '@babel/core': 7.29.7 + '@babel/core': 7.29.7(supports-color@8.1.1) '@babel/helper-plugin-utils': 7.29.7 - '@babel/helper-remap-async-to-generator': 7.29.7(@babel/core@7.29.7) - '@babel/traverse': 7.29.7 + '@babel/helper-remap-async-to-generator': 7.29.7(@babel/core@7.29.7(supports-color@8.1.1))(supports-color@8.1.1) + '@babel/traverse': 7.29.7(supports-color@8.1.1) transitivePeerDependencies: - supports-color - '@babel/plugin-transform-async-to-generator@7.29.7(@babel/core@7.29.7)': + '@babel/plugin-transform-async-to-generator@7.29.7(@babel/core@7.29.7(supports-color@8.1.1))(supports-color@8.1.1)': dependencies: - '@babel/core': 7.29.7 - '@babel/helper-module-imports': 7.29.7 + '@babel/core': 7.29.7(supports-color@8.1.1) + '@babel/helper-module-imports': 7.29.7(supports-color@8.1.1) '@babel/helper-plugin-utils': 7.29.7 - '@babel/helper-remap-async-to-generator': 7.29.7(@babel/core@7.29.7) + '@babel/helper-remap-async-to-generator': 7.29.7(@babel/core@7.29.7(supports-color@8.1.1))(supports-color@8.1.1) transitivePeerDependencies: - supports-color - '@babel/plugin-transform-block-scoped-functions@7.29.7(@babel/core@7.29.7)': + '@babel/plugin-transform-block-scoped-functions@7.29.7(@babel/core@7.29.7(supports-color@8.1.1))': dependencies: - '@babel/core': 7.29.7 + '@babel/core': 7.29.7(supports-color@8.1.1) '@babel/helper-plugin-utils': 7.29.7 - '@babel/plugin-transform-block-scoping@7.29.7(@babel/core@7.29.7)': + '@babel/plugin-transform-block-scoping@7.29.7(@babel/core@7.29.7(supports-color@8.1.1))': dependencies: - '@babel/core': 7.29.7 + '@babel/core': 7.29.7(supports-color@8.1.1) '@babel/helper-plugin-utils': 7.29.7 - '@babel/plugin-transform-class-properties@7.29.7(@babel/core@7.29.7)': + '@babel/plugin-transform-class-properties@7.29.7(@babel/core@7.29.7(supports-color@8.1.1))(supports-color@8.1.1)': dependencies: - '@babel/core': 7.29.7 - '@babel/helper-create-class-features-plugin': 7.29.7(@babel/core@7.29.7) + '@babel/core': 7.29.7(supports-color@8.1.1) + '@babel/helper-create-class-features-plugin': 7.29.7(@babel/core@7.29.7(supports-color@8.1.1))(supports-color@8.1.1) '@babel/helper-plugin-utils': 7.29.7 transitivePeerDependencies: - supports-color - '@babel/plugin-transform-class-static-block@7.29.7(@babel/core@7.29.7)': + '@babel/plugin-transform-class-static-block@7.29.7(@babel/core@7.29.7(supports-color@8.1.1))(supports-color@8.1.1)': dependencies: - '@babel/core': 7.29.7 - '@babel/helper-create-class-features-plugin': 7.29.7(@babel/core@7.29.7) + '@babel/core': 7.29.7(supports-color@8.1.1) + '@babel/helper-create-class-features-plugin': 7.29.7(@babel/core@7.29.7(supports-color@8.1.1))(supports-color@8.1.1) '@babel/helper-plugin-utils': 7.29.7 transitivePeerDependencies: - supports-color - '@babel/plugin-transform-classes@7.29.7(@babel/core@7.29.7)': + '@babel/plugin-transform-classes@7.29.7(@babel/core@7.29.7(supports-color@8.1.1))(supports-color@8.1.1)': dependencies: - '@babel/core': 7.29.7 + '@babel/core': 7.29.7(supports-color@8.1.1) '@babel/helper-annotate-as-pure': 7.29.7 '@babel/helper-compilation-targets': 7.29.7 '@babel/helper-globals': 7.29.7 '@babel/helper-plugin-utils': 7.29.7 - '@babel/helper-replace-supers': 7.29.7(@babel/core@7.29.7) - '@babel/traverse': 7.29.7 + '@babel/helper-replace-supers': 7.29.7(@babel/core@7.29.7(supports-color@8.1.1))(supports-color@8.1.1) + '@babel/traverse': 7.29.7(supports-color@8.1.1) transitivePeerDependencies: - supports-color - '@babel/plugin-transform-computed-properties@7.29.7(@babel/core@7.29.7)': + '@babel/plugin-transform-computed-properties@7.29.7(@babel/core@7.29.7(supports-color@8.1.1))': dependencies: - '@babel/core': 7.29.7 + '@babel/core': 7.29.7(supports-color@8.1.1) '@babel/helper-plugin-utils': 7.29.7 '@babel/template': 7.29.7 - '@babel/plugin-transform-destructuring@7.29.7(@babel/core@7.29.7)': + '@babel/plugin-transform-destructuring@7.29.7(@babel/core@7.29.7(supports-color@8.1.1))(supports-color@8.1.1)': dependencies: - '@babel/core': 7.29.7 + '@babel/core': 7.29.7(supports-color@8.1.1) '@babel/helper-plugin-utils': 7.29.7 - '@babel/traverse': 7.29.7 + '@babel/traverse': 7.29.7(supports-color@8.1.1) transitivePeerDependencies: - supports-color - '@babel/plugin-transform-dotall-regex@7.29.7(@babel/core@7.29.7)': + '@babel/plugin-transform-dotall-regex@7.29.7(@babel/core@7.29.7(supports-color@8.1.1))': dependencies: - '@babel/core': 7.29.7 - '@babel/helper-create-regexp-features-plugin': 7.29.7(@babel/core@7.29.7) + '@babel/core': 7.29.7(supports-color@8.1.1) + '@babel/helper-create-regexp-features-plugin': 7.29.7(@babel/core@7.29.7(supports-color@8.1.1)) '@babel/helper-plugin-utils': 7.29.7 - '@babel/plugin-transform-duplicate-keys@7.29.7(@babel/core@7.29.7)': + '@babel/plugin-transform-duplicate-keys@7.29.7(@babel/core@7.29.7(supports-color@8.1.1))': dependencies: - '@babel/core': 7.29.7 + '@babel/core': 7.29.7(supports-color@8.1.1) '@babel/helper-plugin-utils': 7.29.7 - '@babel/plugin-transform-duplicate-named-capturing-groups-regex@7.29.7(@babel/core@7.29.7)': + '@babel/plugin-transform-duplicate-named-capturing-groups-regex@7.29.7(@babel/core@7.29.7(supports-color@8.1.1))': dependencies: - '@babel/core': 7.29.7 - '@babel/helper-create-regexp-features-plugin': 7.29.7(@babel/core@7.29.7) + '@babel/core': 7.29.7(supports-color@8.1.1) + '@babel/helper-create-regexp-features-plugin': 7.29.7(@babel/core@7.29.7(supports-color@8.1.1)) '@babel/helper-plugin-utils': 7.29.7 - '@babel/plugin-transform-dynamic-import@7.29.7(@babel/core@7.29.7)': + '@babel/plugin-transform-dynamic-import@7.29.7(@babel/core@7.29.7(supports-color@8.1.1))': dependencies: - '@babel/core': 7.29.7 + '@babel/core': 7.29.7(supports-color@8.1.1) '@babel/helper-plugin-utils': 7.29.7 - '@babel/plugin-transform-explicit-resource-management@7.29.7(@babel/core@7.29.7)': + '@babel/plugin-transform-explicit-resource-management@7.29.7(@babel/core@7.29.7(supports-color@8.1.1))(supports-color@8.1.1)': dependencies: - '@babel/core': 7.29.7 + '@babel/core': 7.29.7(supports-color@8.1.1) '@babel/helper-plugin-utils': 7.29.7 - '@babel/plugin-transform-destructuring': 7.29.7(@babel/core@7.29.7) + '@babel/plugin-transform-destructuring': 7.29.7(@babel/core@7.29.7(supports-color@8.1.1))(supports-color@8.1.1) transitivePeerDependencies: - supports-color - '@babel/plugin-transform-exponentiation-operator@7.29.7(@babel/core@7.29.7)': + '@babel/plugin-transform-exponentiation-operator@7.29.7(@babel/core@7.29.7(supports-color@8.1.1))': dependencies: - '@babel/core': 7.29.7 + '@babel/core': 7.29.7(supports-color@8.1.1) '@babel/helper-plugin-utils': 7.29.7 - '@babel/plugin-transform-export-namespace-from@7.29.7(@babel/core@7.29.7)': + '@babel/plugin-transform-export-namespace-from@7.29.7(@babel/core@7.29.7(supports-color@8.1.1))': dependencies: - '@babel/core': 7.29.7 + '@babel/core': 7.29.7(supports-color@8.1.1) '@babel/helper-plugin-utils': 7.29.7 - '@babel/plugin-transform-flow-strip-types@7.29.7(@babel/core@7.29.7)': + '@babel/plugin-transform-flow-strip-types@7.29.7(@babel/core@7.29.7(supports-color@8.1.1))': dependencies: - '@babel/core': 7.29.7 + '@babel/core': 7.29.7(supports-color@8.1.1) '@babel/helper-plugin-utils': 7.29.7 - '@babel/plugin-syntax-flow': 7.29.7(@babel/core@7.29.7) + '@babel/plugin-syntax-flow': 7.29.7(@babel/core@7.29.7(supports-color@8.1.1)) - '@babel/plugin-transform-for-of@7.29.7(@babel/core@7.29.7)': + '@babel/plugin-transform-for-of@7.29.7(@babel/core@7.29.7(supports-color@8.1.1))(supports-color@8.1.1)': dependencies: - '@babel/core': 7.29.7 + '@babel/core': 7.29.7(supports-color@8.1.1) '@babel/helper-plugin-utils': 7.29.7 - '@babel/helper-skip-transparent-expression-wrappers': 7.29.7 + '@babel/helper-skip-transparent-expression-wrappers': 7.29.7(supports-color@8.1.1) transitivePeerDependencies: - supports-color - '@babel/plugin-transform-function-name@7.29.7(@babel/core@7.29.7)': + '@babel/plugin-transform-function-name@7.29.7(@babel/core@7.29.7(supports-color@8.1.1))(supports-color@8.1.1)': dependencies: - '@babel/core': 7.29.7 + '@babel/core': 7.29.7(supports-color@8.1.1) '@babel/helper-compilation-targets': 7.29.7 '@babel/helper-plugin-utils': 7.29.7 - '@babel/traverse': 7.29.7 + '@babel/traverse': 7.29.7(supports-color@8.1.1) transitivePeerDependencies: - supports-color - '@babel/plugin-transform-json-strings@7.29.7(@babel/core@7.29.7)': + '@babel/plugin-transform-json-strings@7.29.7(@babel/core@7.29.7(supports-color@8.1.1))': dependencies: - '@babel/core': 7.29.7 + '@babel/core': 7.29.7(supports-color@8.1.1) '@babel/helper-plugin-utils': 7.29.7 - '@babel/plugin-transform-literals@7.29.7(@babel/core@7.29.7)': + '@babel/plugin-transform-literals@7.29.7(@babel/core@7.29.7(supports-color@8.1.1))': dependencies: - '@babel/core': 7.29.7 + '@babel/core': 7.29.7(supports-color@8.1.1) '@babel/helper-plugin-utils': 7.29.7 - '@babel/plugin-transform-logical-assignment-operators@7.29.7(@babel/core@7.29.7)': + '@babel/plugin-transform-logical-assignment-operators@7.29.7(@babel/core@7.29.7(supports-color@8.1.1))': dependencies: - '@babel/core': 7.29.7 + '@babel/core': 7.29.7(supports-color@8.1.1) '@babel/helper-plugin-utils': 7.29.7 - '@babel/plugin-transform-member-expression-literals@7.29.7(@babel/core@7.29.7)': + '@babel/plugin-transform-member-expression-literals@7.29.7(@babel/core@7.29.7(supports-color@8.1.1))': dependencies: - '@babel/core': 7.29.7 + '@babel/core': 7.29.7(supports-color@8.1.1) '@babel/helper-plugin-utils': 7.29.7 - '@babel/plugin-transform-modules-amd@7.29.7(@babel/core@7.29.7)': + '@babel/plugin-transform-modules-amd@7.29.7(@babel/core@7.29.7(supports-color@8.1.1))(supports-color@8.1.1)': dependencies: - '@babel/core': 7.29.7 - '@babel/helper-module-transforms': 7.29.7(@babel/core@7.29.7) + '@babel/core': 7.29.7(supports-color@8.1.1) + '@babel/helper-module-transforms': 7.29.7(@babel/core@7.29.7(supports-color@8.1.1))(supports-color@8.1.1) '@babel/helper-plugin-utils': 7.29.7 transitivePeerDependencies: - supports-color - '@babel/plugin-transform-modules-commonjs@7.29.7(@babel/core@7.29.7)': + '@babel/plugin-transform-modules-commonjs@7.29.7(@babel/core@7.29.7(supports-color@8.1.1))(supports-color@8.1.1)': dependencies: - '@babel/core': 7.29.7 - '@babel/helper-module-transforms': 7.29.7(@babel/core@7.29.7) + '@babel/core': 7.29.7(supports-color@8.1.1) + '@babel/helper-module-transforms': 7.29.7(@babel/core@7.29.7(supports-color@8.1.1))(supports-color@8.1.1) '@babel/helper-plugin-utils': 7.29.7 transitivePeerDependencies: - supports-color - '@babel/plugin-transform-modules-systemjs@7.29.7(@babel/core@7.29.7)': + '@babel/plugin-transform-modules-systemjs@7.29.7(@babel/core@7.29.7(supports-color@8.1.1))(supports-color@8.1.1)': dependencies: - '@babel/core': 7.29.7 - '@babel/helper-module-transforms': 7.29.7(@babel/core@7.29.7) + '@babel/core': 7.29.7(supports-color@8.1.1) + '@babel/helper-module-transforms': 7.29.7(@babel/core@7.29.7(supports-color@8.1.1))(supports-color@8.1.1) '@babel/helper-plugin-utils': 7.29.7 '@babel/helper-validator-identifier': 7.29.7 - '@babel/traverse': 7.29.7 + '@babel/traverse': 7.29.7(supports-color@8.1.1) transitivePeerDependencies: - supports-color - '@babel/plugin-transform-modules-umd@7.29.7(@babel/core@7.29.7)': + '@babel/plugin-transform-modules-umd@7.29.7(@babel/core@7.29.7(supports-color@8.1.1))(supports-color@8.1.1)': dependencies: - '@babel/core': 7.29.7 - '@babel/helper-module-transforms': 7.29.7(@babel/core@7.29.7) + '@babel/core': 7.29.7(supports-color@8.1.1) + '@babel/helper-module-transforms': 7.29.7(@babel/core@7.29.7(supports-color@8.1.1))(supports-color@8.1.1) '@babel/helper-plugin-utils': 7.29.7 transitivePeerDependencies: - supports-color - '@babel/plugin-transform-named-capturing-groups-regex@7.29.7(@babel/core@7.29.7)': + '@babel/plugin-transform-named-capturing-groups-regex@7.29.7(@babel/core@7.29.7(supports-color@8.1.1))': dependencies: - '@babel/core': 7.29.7 - '@babel/helper-create-regexp-features-plugin': 7.29.7(@babel/core@7.29.7) + '@babel/core': 7.29.7(supports-color@8.1.1) + '@babel/helper-create-regexp-features-plugin': 7.29.7(@babel/core@7.29.7(supports-color@8.1.1)) '@babel/helper-plugin-utils': 7.29.7 - '@babel/plugin-transform-new-target@7.29.7(@babel/core@7.29.7)': + '@babel/plugin-transform-new-target@7.29.7(@babel/core@7.29.7(supports-color@8.1.1))': dependencies: - '@babel/core': 7.29.7 + '@babel/core': 7.29.7(supports-color@8.1.1) '@babel/helper-plugin-utils': 7.29.7 - '@babel/plugin-transform-nullish-coalescing-operator@7.29.7(@babel/core@7.29.7)': + '@babel/plugin-transform-nullish-coalescing-operator@7.29.7(@babel/core@7.29.7(supports-color@8.1.1))': dependencies: - '@babel/core': 7.29.7 + '@babel/core': 7.29.7(supports-color@8.1.1) '@babel/helper-plugin-utils': 7.29.7 - '@babel/plugin-transform-numeric-separator@7.29.7(@babel/core@7.29.7)': + '@babel/plugin-transform-numeric-separator@7.29.7(@babel/core@7.29.7(supports-color@8.1.1))': dependencies: - '@babel/core': 7.29.7 + '@babel/core': 7.29.7(supports-color@8.1.1) '@babel/helper-plugin-utils': 7.29.7 - '@babel/plugin-transform-object-rest-spread@7.29.7(@babel/core@7.29.7)': + '@babel/plugin-transform-object-rest-spread@7.29.7(@babel/core@7.29.7(supports-color@8.1.1))(supports-color@8.1.1)': dependencies: - '@babel/core': 7.29.7 + '@babel/core': 7.29.7(supports-color@8.1.1) '@babel/helper-compilation-targets': 7.29.7 '@babel/helper-plugin-utils': 7.29.7 - '@babel/plugin-transform-destructuring': 7.29.7(@babel/core@7.29.7) - '@babel/plugin-transform-parameters': 7.29.7(@babel/core@7.29.7) - '@babel/traverse': 7.29.7 + '@babel/plugin-transform-destructuring': 7.29.7(@babel/core@7.29.7(supports-color@8.1.1))(supports-color@8.1.1) + '@babel/plugin-transform-parameters': 7.29.7(@babel/core@7.29.7(supports-color@8.1.1)) + '@babel/traverse': 7.29.7(supports-color@8.1.1) transitivePeerDependencies: - supports-color - '@babel/plugin-transform-object-super@7.29.7(@babel/core@7.29.7)': + '@babel/plugin-transform-object-super@7.29.7(@babel/core@7.29.7(supports-color@8.1.1))(supports-color@8.1.1)': dependencies: - '@babel/core': 7.29.7 + '@babel/core': 7.29.7(supports-color@8.1.1) '@babel/helper-plugin-utils': 7.29.7 - '@babel/helper-replace-supers': 7.29.7(@babel/core@7.29.7) + '@babel/helper-replace-supers': 7.29.7(@babel/core@7.29.7(supports-color@8.1.1))(supports-color@8.1.1) transitivePeerDependencies: - supports-color - '@babel/plugin-transform-optional-catch-binding@7.29.7(@babel/core@7.29.7)': + '@babel/plugin-transform-optional-catch-binding@7.29.7(@babel/core@7.29.7(supports-color@8.1.1))': dependencies: - '@babel/core': 7.29.7 + '@babel/core': 7.29.7(supports-color@8.1.1) '@babel/helper-plugin-utils': 7.29.7 - '@babel/plugin-transform-optional-chaining@7.29.7(@babel/core@7.29.7)': + '@babel/plugin-transform-optional-chaining@7.29.7(@babel/core@7.29.7(supports-color@8.1.1))(supports-color@8.1.1)': dependencies: - '@babel/core': 7.29.7 + '@babel/core': 7.29.7(supports-color@8.1.1) '@babel/helper-plugin-utils': 7.29.7 - '@babel/helper-skip-transparent-expression-wrappers': 7.29.7 + '@babel/helper-skip-transparent-expression-wrappers': 7.29.7(supports-color@8.1.1) transitivePeerDependencies: - supports-color - '@babel/plugin-transform-parameters@7.29.7(@babel/core@7.29.7)': + '@babel/plugin-transform-parameters@7.29.7(@babel/core@7.29.7(supports-color@8.1.1))': dependencies: - '@babel/core': 7.29.7 + '@babel/core': 7.29.7(supports-color@8.1.1) '@babel/helper-plugin-utils': 7.29.7 - '@babel/plugin-transform-private-methods@7.29.7(@babel/core@7.29.7)': + '@babel/plugin-transform-private-methods@7.29.7(@babel/core@7.29.7(supports-color@8.1.1))(supports-color@8.1.1)': dependencies: - '@babel/core': 7.29.7 - '@babel/helper-create-class-features-plugin': 7.29.7(@babel/core@7.29.7) + '@babel/core': 7.29.7(supports-color@8.1.1) + '@babel/helper-create-class-features-plugin': 7.29.7(@babel/core@7.29.7(supports-color@8.1.1))(supports-color@8.1.1) '@babel/helper-plugin-utils': 7.29.7 transitivePeerDependencies: - supports-color - '@babel/plugin-transform-private-property-in-object@7.29.7(@babel/core@7.29.7)': + '@babel/plugin-transform-private-property-in-object@7.29.7(@babel/core@7.29.7(supports-color@8.1.1))(supports-color@8.1.1)': dependencies: - '@babel/core': 7.29.7 + '@babel/core': 7.29.7(supports-color@8.1.1) '@babel/helper-annotate-as-pure': 7.29.7 - '@babel/helper-create-class-features-plugin': 7.29.7(@babel/core@7.29.7) + '@babel/helper-create-class-features-plugin': 7.29.7(@babel/core@7.29.7(supports-color@8.1.1))(supports-color@8.1.1) '@babel/helper-plugin-utils': 7.29.7 transitivePeerDependencies: - supports-color - '@babel/plugin-transform-property-literals@7.29.7(@babel/core@7.29.7)': + '@babel/plugin-transform-property-literals@7.29.7(@babel/core@7.29.7(supports-color@8.1.1))': dependencies: - '@babel/core': 7.29.7 + '@babel/core': 7.29.7(supports-color@8.1.1) '@babel/helper-plugin-utils': 7.29.7 - '@babel/plugin-transform-react-constant-elements@7.29.7(@babel/core@7.29.7)': + '@babel/plugin-transform-react-constant-elements@7.29.7(@babel/core@7.29.7(supports-color@8.1.1))': dependencies: - '@babel/core': 7.29.7 + '@babel/core': 7.29.7(supports-color@8.1.1) '@babel/helper-plugin-utils': 7.29.7 - '@babel/plugin-transform-react-display-name@7.29.7(@babel/core@7.29.7)': + '@babel/plugin-transform-react-display-name@7.29.7(@babel/core@7.29.7(supports-color@8.1.1))': dependencies: - '@babel/core': 7.29.7 + '@babel/core': 7.29.7(supports-color@8.1.1) '@babel/helper-plugin-utils': 7.29.7 - '@babel/plugin-transform-react-jsx-development@7.29.7(@babel/core@7.29.7)': + '@babel/plugin-transform-react-jsx-development@7.29.7(@babel/core@7.29.7(supports-color@8.1.1))(supports-color@8.1.1)': dependencies: - '@babel/core': 7.29.7 - '@babel/plugin-transform-react-jsx': 7.29.7(@babel/core@7.29.7) + '@babel/core': 7.29.7(supports-color@8.1.1) + '@babel/plugin-transform-react-jsx': 7.29.7(@babel/core@7.29.7(supports-color@8.1.1))(supports-color@8.1.1) transitivePeerDependencies: - supports-color - '@babel/plugin-transform-react-jsx@7.29.7(@babel/core@7.29.7)': + '@babel/plugin-transform-react-jsx@7.29.7(@babel/core@7.29.7(supports-color@8.1.1))(supports-color@8.1.1)': dependencies: - '@babel/core': 7.29.7 + '@babel/core': 7.29.7(supports-color@8.1.1) '@babel/helper-annotate-as-pure': 7.29.7 - '@babel/helper-module-imports': 7.29.7 + '@babel/helper-module-imports': 7.29.7(supports-color@8.1.1) '@babel/helper-plugin-utils': 7.29.7 - '@babel/plugin-syntax-jsx': 7.29.7(@babel/core@7.29.7) + '@babel/plugin-syntax-jsx': 7.29.7(@babel/core@7.29.7(supports-color@8.1.1)) '@babel/types': 7.29.7 transitivePeerDependencies: - supports-color - '@babel/plugin-transform-react-pure-annotations@7.29.7(@babel/core@7.29.7)': + '@babel/plugin-transform-react-pure-annotations@7.29.7(@babel/core@7.29.7(supports-color@8.1.1))': dependencies: - '@babel/core': 7.29.7 + '@babel/core': 7.29.7(supports-color@8.1.1) '@babel/helper-annotate-as-pure': 7.29.7 '@babel/helper-plugin-utils': 7.29.7 - '@babel/plugin-transform-regenerator@7.29.7(@babel/core@7.29.7)': + '@babel/plugin-transform-regenerator@7.29.7(@babel/core@7.29.7(supports-color@8.1.1))': dependencies: - '@babel/core': 7.29.7 + '@babel/core': 7.29.7(supports-color@8.1.1) '@babel/helper-plugin-utils': 7.29.7 - '@babel/plugin-transform-regexp-modifiers@7.29.7(@babel/core@7.29.7)': + '@babel/plugin-transform-regexp-modifiers@7.29.7(@babel/core@7.29.7(supports-color@8.1.1))': dependencies: - '@babel/core': 7.29.7 - '@babel/helper-create-regexp-features-plugin': 7.29.7(@babel/core@7.29.7) + '@babel/core': 7.29.7(supports-color@8.1.1) + '@babel/helper-create-regexp-features-plugin': 7.29.7(@babel/core@7.29.7(supports-color@8.1.1)) '@babel/helper-plugin-utils': 7.29.7 - '@babel/plugin-transform-reserved-words@7.29.7(@babel/core@7.29.7)': + '@babel/plugin-transform-reserved-words@7.29.7(@babel/core@7.29.7(supports-color@8.1.1))': dependencies: - '@babel/core': 7.29.7 + '@babel/core': 7.29.7(supports-color@8.1.1) '@babel/helper-plugin-utils': 7.29.7 - '@babel/plugin-transform-runtime@7.29.7(@babel/core@7.29.7)': + '@babel/plugin-transform-runtime@7.29.7(@babel/core@7.29.7(supports-color@8.1.1))(supports-color@8.1.1)': dependencies: - '@babel/core': 7.29.7 - '@babel/helper-module-imports': 7.29.7 + '@babel/core': 7.29.7(supports-color@8.1.1) + '@babel/helper-module-imports': 7.29.7(supports-color@8.1.1) '@babel/helper-plugin-utils': 7.29.7 - babel-plugin-polyfill-corejs2: 0.4.17(@babel/core@7.29.7) - babel-plugin-polyfill-corejs3: 0.13.0(@babel/core@7.29.7) - babel-plugin-polyfill-regenerator: 0.6.8(@babel/core@7.29.7) + babel-plugin-polyfill-corejs2: 0.4.17(@babel/core@7.29.7(supports-color@8.1.1))(supports-color@8.1.1) + babel-plugin-polyfill-corejs3: 0.13.0(@babel/core@7.29.7(supports-color@8.1.1))(supports-color@8.1.1) + babel-plugin-polyfill-regenerator: 0.6.8(@babel/core@7.29.7(supports-color@8.1.1))(supports-color@8.1.1) semver: 6.3.1 transitivePeerDependencies: - supports-color - '@babel/plugin-transform-shorthand-properties@7.29.7(@babel/core@7.29.7)': + '@babel/plugin-transform-shorthand-properties@7.29.7(@babel/core@7.29.7(supports-color@8.1.1))': dependencies: - '@babel/core': 7.29.7 + '@babel/core': 7.29.7(supports-color@8.1.1) '@babel/helper-plugin-utils': 7.29.7 - '@babel/plugin-transform-spread@7.29.7(@babel/core@7.29.7)': + '@babel/plugin-transform-spread@7.29.7(@babel/core@7.29.7(supports-color@8.1.1))(supports-color@8.1.1)': dependencies: - '@babel/core': 7.29.7 + '@babel/core': 7.29.7(supports-color@8.1.1) '@babel/helper-plugin-utils': 7.29.7 - '@babel/helper-skip-transparent-expression-wrappers': 7.29.7 + '@babel/helper-skip-transparent-expression-wrappers': 7.29.7(supports-color@8.1.1) transitivePeerDependencies: - supports-color - '@babel/plugin-transform-sticky-regex@7.29.7(@babel/core@7.29.7)': + '@babel/plugin-transform-sticky-regex@7.29.7(@babel/core@7.29.7(supports-color@8.1.1))': dependencies: - '@babel/core': 7.29.7 + '@babel/core': 7.29.7(supports-color@8.1.1) '@babel/helper-plugin-utils': 7.29.7 - '@babel/plugin-transform-template-literals@7.29.7(@babel/core@7.29.7)': + '@babel/plugin-transform-template-literals@7.29.7(@babel/core@7.29.7(supports-color@8.1.1))': dependencies: - '@babel/core': 7.29.7 + '@babel/core': 7.29.7(supports-color@8.1.1) '@babel/helper-plugin-utils': 7.29.7 - '@babel/plugin-transform-typeof-symbol@7.29.7(@babel/core@7.29.7)': + '@babel/plugin-transform-typeof-symbol@7.29.7(@babel/core@7.29.7(supports-color@8.1.1))': dependencies: - '@babel/core': 7.29.7 + '@babel/core': 7.29.7(supports-color@8.1.1) '@babel/helper-plugin-utils': 7.29.7 - '@babel/plugin-transform-typescript@7.29.7(@babel/core@7.29.7)': + '@babel/plugin-transform-typescript@7.29.7(@babel/core@7.29.7(supports-color@8.1.1))(supports-color@8.1.1)': dependencies: - '@babel/core': 7.29.7 + '@babel/core': 7.29.7(supports-color@8.1.1) '@babel/helper-annotate-as-pure': 7.29.7 - '@babel/helper-create-class-features-plugin': 7.29.7(@babel/core@7.29.7) + '@babel/helper-create-class-features-plugin': 7.29.7(@babel/core@7.29.7(supports-color@8.1.1))(supports-color@8.1.1) '@babel/helper-plugin-utils': 7.29.7 - '@babel/helper-skip-transparent-expression-wrappers': 7.29.7 - '@babel/plugin-syntax-typescript': 7.29.7(@babel/core@7.29.7) + '@babel/helper-skip-transparent-expression-wrappers': 7.29.7(supports-color@8.1.1) + '@babel/plugin-syntax-typescript': 7.29.7(@babel/core@7.29.7(supports-color@8.1.1)) transitivePeerDependencies: - supports-color - '@babel/plugin-transform-unicode-escapes@7.29.7(@babel/core@7.29.7)': + '@babel/plugin-transform-unicode-escapes@7.29.7(@babel/core@7.29.7(supports-color@8.1.1))': dependencies: - '@babel/core': 7.29.7 + '@babel/core': 7.29.7(supports-color@8.1.1) '@babel/helper-plugin-utils': 7.29.7 - '@babel/plugin-transform-unicode-property-regex@7.29.7(@babel/core@7.29.7)': + '@babel/plugin-transform-unicode-property-regex@7.29.7(@babel/core@7.29.7(supports-color@8.1.1))': dependencies: - '@babel/core': 7.29.7 - '@babel/helper-create-regexp-features-plugin': 7.29.7(@babel/core@7.29.7) + '@babel/core': 7.29.7(supports-color@8.1.1) + '@babel/helper-create-regexp-features-plugin': 7.29.7(@babel/core@7.29.7(supports-color@8.1.1)) '@babel/helper-plugin-utils': 7.29.7 - '@babel/plugin-transform-unicode-regex@7.29.7(@babel/core@7.29.7)': + '@babel/plugin-transform-unicode-regex@7.29.7(@babel/core@7.29.7(supports-color@8.1.1))': dependencies: - '@babel/core': 7.29.7 - '@babel/helper-create-regexp-features-plugin': 7.29.7(@babel/core@7.29.7) + '@babel/core': 7.29.7(supports-color@8.1.1) + '@babel/helper-create-regexp-features-plugin': 7.29.7(@babel/core@7.29.7(supports-color@8.1.1)) '@babel/helper-plugin-utils': 7.29.7 - '@babel/plugin-transform-unicode-sets-regex@7.29.7(@babel/core@7.29.7)': + '@babel/plugin-transform-unicode-sets-regex@7.29.7(@babel/core@7.29.7(supports-color@8.1.1))': dependencies: - '@babel/core': 7.29.7 - '@babel/helper-create-regexp-features-plugin': 7.29.7(@babel/core@7.29.7) + '@babel/core': 7.29.7(supports-color@8.1.1) + '@babel/helper-create-regexp-features-plugin': 7.29.7(@babel/core@7.29.7(supports-color@8.1.1)) '@babel/helper-plugin-utils': 7.29.7 - '@babel/preset-env@7.29.7(@babel/core@7.29.7)': + '@babel/preset-env@7.29.7(@babel/core@7.29.7(supports-color@8.1.1))(supports-color@8.1.1)': dependencies: '@babel/compat-data': 7.29.7 - '@babel/core': 7.29.7 + '@babel/core': 7.29.7(supports-color@8.1.1) '@babel/helper-compilation-targets': 7.29.7 '@babel/helper-plugin-utils': 7.29.7 '@babel/helper-validator-option': 7.29.7 - '@babel/plugin-bugfix-firefox-class-in-computed-class-key': 7.29.7(@babel/core@7.29.7) - '@babel/plugin-bugfix-safari-class-field-initializer-scope': 7.29.7(@babel/core@7.29.7) - '@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression': 7.29.7(@babel/core@7.29.7) - '@babel/plugin-bugfix-safari-rest-destructuring-rhs-array': 7.29.7(@babel/core@7.29.7) - '@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining': 7.29.7(@babel/core@7.29.7) - '@babel/plugin-bugfix-v8-static-class-fields-redefine-readonly': 7.29.7(@babel/core@7.29.7) - '@babel/plugin-proposal-private-property-in-object': 7.21.0-placeholder-for-preset-env.2(@babel/core@7.29.7) - '@babel/plugin-syntax-import-assertions': 7.29.7(@babel/core@7.29.7) - '@babel/plugin-syntax-import-attributes': 7.29.7(@babel/core@7.29.7) - '@babel/plugin-syntax-unicode-sets-regex': 7.18.6(@babel/core@7.29.7) - '@babel/plugin-transform-arrow-functions': 7.29.7(@babel/core@7.29.7) - '@babel/plugin-transform-async-generator-functions': 7.29.7(@babel/core@7.29.7) - '@babel/plugin-transform-async-to-generator': 7.29.7(@babel/core@7.29.7) - '@babel/plugin-transform-block-scoped-functions': 7.29.7(@babel/core@7.29.7) - '@babel/plugin-transform-block-scoping': 7.29.7(@babel/core@7.29.7) - '@babel/plugin-transform-class-properties': 7.29.7(@babel/core@7.29.7) - '@babel/plugin-transform-class-static-block': 7.29.7(@babel/core@7.29.7) - '@babel/plugin-transform-classes': 7.29.7(@babel/core@7.29.7) - '@babel/plugin-transform-computed-properties': 7.29.7(@babel/core@7.29.7) - '@babel/plugin-transform-destructuring': 7.29.7(@babel/core@7.29.7) - '@babel/plugin-transform-dotall-regex': 7.29.7(@babel/core@7.29.7) - '@babel/plugin-transform-duplicate-keys': 7.29.7(@babel/core@7.29.7) - '@babel/plugin-transform-duplicate-named-capturing-groups-regex': 7.29.7(@babel/core@7.29.7) - '@babel/plugin-transform-dynamic-import': 7.29.7(@babel/core@7.29.7) - '@babel/plugin-transform-explicit-resource-management': 7.29.7(@babel/core@7.29.7) - '@babel/plugin-transform-exponentiation-operator': 7.29.7(@babel/core@7.29.7) - '@babel/plugin-transform-export-namespace-from': 7.29.7(@babel/core@7.29.7) - '@babel/plugin-transform-for-of': 7.29.7(@babel/core@7.29.7) - '@babel/plugin-transform-function-name': 7.29.7(@babel/core@7.29.7) - '@babel/plugin-transform-json-strings': 7.29.7(@babel/core@7.29.7) - '@babel/plugin-transform-literals': 7.29.7(@babel/core@7.29.7) - '@babel/plugin-transform-logical-assignment-operators': 7.29.7(@babel/core@7.29.7) - '@babel/plugin-transform-member-expression-literals': 7.29.7(@babel/core@7.29.7) - '@babel/plugin-transform-modules-amd': 7.29.7(@babel/core@7.29.7) - '@babel/plugin-transform-modules-commonjs': 7.29.7(@babel/core@7.29.7) - '@babel/plugin-transform-modules-systemjs': 7.29.7(@babel/core@7.29.7) - '@babel/plugin-transform-modules-umd': 7.29.7(@babel/core@7.29.7) - '@babel/plugin-transform-named-capturing-groups-regex': 7.29.7(@babel/core@7.29.7) - '@babel/plugin-transform-new-target': 7.29.7(@babel/core@7.29.7) - '@babel/plugin-transform-nullish-coalescing-operator': 7.29.7(@babel/core@7.29.7) - '@babel/plugin-transform-numeric-separator': 7.29.7(@babel/core@7.29.7) - '@babel/plugin-transform-object-rest-spread': 7.29.7(@babel/core@7.29.7) - '@babel/plugin-transform-object-super': 7.29.7(@babel/core@7.29.7) - '@babel/plugin-transform-optional-catch-binding': 7.29.7(@babel/core@7.29.7) - '@babel/plugin-transform-optional-chaining': 7.29.7(@babel/core@7.29.7) - '@babel/plugin-transform-parameters': 7.29.7(@babel/core@7.29.7) - '@babel/plugin-transform-private-methods': 7.29.7(@babel/core@7.29.7) - '@babel/plugin-transform-private-property-in-object': 7.29.7(@babel/core@7.29.7) - '@babel/plugin-transform-property-literals': 7.29.7(@babel/core@7.29.7) - '@babel/plugin-transform-regenerator': 7.29.7(@babel/core@7.29.7) - '@babel/plugin-transform-regexp-modifiers': 7.29.7(@babel/core@7.29.7) - '@babel/plugin-transform-reserved-words': 7.29.7(@babel/core@7.29.7) - '@babel/plugin-transform-shorthand-properties': 7.29.7(@babel/core@7.29.7) - '@babel/plugin-transform-spread': 7.29.7(@babel/core@7.29.7) - '@babel/plugin-transform-sticky-regex': 7.29.7(@babel/core@7.29.7) - '@babel/plugin-transform-template-literals': 7.29.7(@babel/core@7.29.7) - '@babel/plugin-transform-typeof-symbol': 7.29.7(@babel/core@7.29.7) - '@babel/plugin-transform-unicode-escapes': 7.29.7(@babel/core@7.29.7) - '@babel/plugin-transform-unicode-property-regex': 7.29.7(@babel/core@7.29.7) - '@babel/plugin-transform-unicode-regex': 7.29.7(@babel/core@7.29.7) - '@babel/plugin-transform-unicode-sets-regex': 7.29.7(@babel/core@7.29.7) - '@babel/preset-modules': 0.1.6-no-external-plugins(@babel/core@7.29.7) - babel-plugin-polyfill-corejs2: 0.4.17(@babel/core@7.29.7) - babel-plugin-polyfill-corejs3: 0.14.2(@babel/core@7.29.7) - babel-plugin-polyfill-regenerator: 0.6.8(@babel/core@7.29.7) + '@babel/plugin-bugfix-firefox-class-in-computed-class-key': 7.29.7(@babel/core@7.29.7(supports-color@8.1.1))(supports-color@8.1.1) + '@babel/plugin-bugfix-safari-class-field-initializer-scope': 7.29.7(@babel/core@7.29.7(supports-color@8.1.1)) + '@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression': 7.29.7(@babel/core@7.29.7(supports-color@8.1.1)) + '@babel/plugin-bugfix-safari-rest-destructuring-rhs-array': 7.29.7(@babel/core@7.29.7(supports-color@8.1.1))(supports-color@8.1.1) + '@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining': 7.29.7(@babel/core@7.29.7(supports-color@8.1.1))(supports-color@8.1.1) + '@babel/plugin-bugfix-v8-static-class-fields-redefine-readonly': 7.29.7(@babel/core@7.29.7(supports-color@8.1.1))(supports-color@8.1.1) + '@babel/plugin-proposal-private-property-in-object': 7.21.0-placeholder-for-preset-env.2(@babel/core@7.29.7(supports-color@8.1.1)) + '@babel/plugin-syntax-import-assertions': 7.29.7(@babel/core@7.29.7(supports-color@8.1.1)) + '@babel/plugin-syntax-import-attributes': 7.29.7(@babel/core@7.29.7(supports-color@8.1.1)) + '@babel/plugin-syntax-unicode-sets-regex': 7.18.6(@babel/core@7.29.7(supports-color@8.1.1)) + '@babel/plugin-transform-arrow-functions': 7.29.7(@babel/core@7.29.7(supports-color@8.1.1)) + '@babel/plugin-transform-async-generator-functions': 7.29.7(@babel/core@7.29.7(supports-color@8.1.1))(supports-color@8.1.1) + '@babel/plugin-transform-async-to-generator': 7.29.7(@babel/core@7.29.7(supports-color@8.1.1))(supports-color@8.1.1) + '@babel/plugin-transform-block-scoped-functions': 7.29.7(@babel/core@7.29.7(supports-color@8.1.1)) + '@babel/plugin-transform-block-scoping': 7.29.7(@babel/core@7.29.7(supports-color@8.1.1)) + '@babel/plugin-transform-class-properties': 7.29.7(@babel/core@7.29.7(supports-color@8.1.1))(supports-color@8.1.1) + '@babel/plugin-transform-class-static-block': 7.29.7(@babel/core@7.29.7(supports-color@8.1.1))(supports-color@8.1.1) + '@babel/plugin-transform-classes': 7.29.7(@babel/core@7.29.7(supports-color@8.1.1))(supports-color@8.1.1) + '@babel/plugin-transform-computed-properties': 7.29.7(@babel/core@7.29.7(supports-color@8.1.1)) + '@babel/plugin-transform-destructuring': 7.29.7(@babel/core@7.29.7(supports-color@8.1.1))(supports-color@8.1.1) + '@babel/plugin-transform-dotall-regex': 7.29.7(@babel/core@7.29.7(supports-color@8.1.1)) + '@babel/plugin-transform-duplicate-keys': 7.29.7(@babel/core@7.29.7(supports-color@8.1.1)) + '@babel/plugin-transform-duplicate-named-capturing-groups-regex': 7.29.7(@babel/core@7.29.7(supports-color@8.1.1)) + '@babel/plugin-transform-dynamic-import': 7.29.7(@babel/core@7.29.7(supports-color@8.1.1)) + '@babel/plugin-transform-explicit-resource-management': 7.29.7(@babel/core@7.29.7(supports-color@8.1.1))(supports-color@8.1.1) + '@babel/plugin-transform-exponentiation-operator': 7.29.7(@babel/core@7.29.7(supports-color@8.1.1)) + '@babel/plugin-transform-export-namespace-from': 7.29.7(@babel/core@7.29.7(supports-color@8.1.1)) + '@babel/plugin-transform-for-of': 7.29.7(@babel/core@7.29.7(supports-color@8.1.1))(supports-color@8.1.1) + '@babel/plugin-transform-function-name': 7.29.7(@babel/core@7.29.7(supports-color@8.1.1))(supports-color@8.1.1) + '@babel/plugin-transform-json-strings': 7.29.7(@babel/core@7.29.7(supports-color@8.1.1)) + '@babel/plugin-transform-literals': 7.29.7(@babel/core@7.29.7(supports-color@8.1.1)) + '@babel/plugin-transform-logical-assignment-operators': 7.29.7(@babel/core@7.29.7(supports-color@8.1.1)) + '@babel/plugin-transform-member-expression-literals': 7.29.7(@babel/core@7.29.7(supports-color@8.1.1)) + '@babel/plugin-transform-modules-amd': 7.29.7(@babel/core@7.29.7(supports-color@8.1.1))(supports-color@8.1.1) + '@babel/plugin-transform-modules-commonjs': 7.29.7(@babel/core@7.29.7(supports-color@8.1.1))(supports-color@8.1.1) + '@babel/plugin-transform-modules-systemjs': 7.29.7(@babel/core@7.29.7(supports-color@8.1.1))(supports-color@8.1.1) + '@babel/plugin-transform-modules-umd': 7.29.7(@babel/core@7.29.7(supports-color@8.1.1))(supports-color@8.1.1) + '@babel/plugin-transform-named-capturing-groups-regex': 7.29.7(@babel/core@7.29.7(supports-color@8.1.1)) + '@babel/plugin-transform-new-target': 7.29.7(@babel/core@7.29.7(supports-color@8.1.1)) + '@babel/plugin-transform-nullish-coalescing-operator': 7.29.7(@babel/core@7.29.7(supports-color@8.1.1)) + '@babel/plugin-transform-numeric-separator': 7.29.7(@babel/core@7.29.7(supports-color@8.1.1)) + '@babel/plugin-transform-object-rest-spread': 7.29.7(@babel/core@7.29.7(supports-color@8.1.1))(supports-color@8.1.1) + '@babel/plugin-transform-object-super': 7.29.7(@babel/core@7.29.7(supports-color@8.1.1))(supports-color@8.1.1) + '@babel/plugin-transform-optional-catch-binding': 7.29.7(@babel/core@7.29.7(supports-color@8.1.1)) + '@babel/plugin-transform-optional-chaining': 7.29.7(@babel/core@7.29.7(supports-color@8.1.1))(supports-color@8.1.1) + '@babel/plugin-transform-parameters': 7.29.7(@babel/core@7.29.7(supports-color@8.1.1)) + '@babel/plugin-transform-private-methods': 7.29.7(@babel/core@7.29.7(supports-color@8.1.1))(supports-color@8.1.1) + '@babel/plugin-transform-private-property-in-object': 7.29.7(@babel/core@7.29.7(supports-color@8.1.1))(supports-color@8.1.1) + '@babel/plugin-transform-property-literals': 7.29.7(@babel/core@7.29.7(supports-color@8.1.1)) + '@babel/plugin-transform-regenerator': 7.29.7(@babel/core@7.29.7(supports-color@8.1.1)) + '@babel/plugin-transform-regexp-modifiers': 7.29.7(@babel/core@7.29.7(supports-color@8.1.1)) + '@babel/plugin-transform-reserved-words': 7.29.7(@babel/core@7.29.7(supports-color@8.1.1)) + '@babel/plugin-transform-shorthand-properties': 7.29.7(@babel/core@7.29.7(supports-color@8.1.1)) + '@babel/plugin-transform-spread': 7.29.7(@babel/core@7.29.7(supports-color@8.1.1))(supports-color@8.1.1) + '@babel/plugin-transform-sticky-regex': 7.29.7(@babel/core@7.29.7(supports-color@8.1.1)) + '@babel/plugin-transform-template-literals': 7.29.7(@babel/core@7.29.7(supports-color@8.1.1)) + '@babel/plugin-transform-typeof-symbol': 7.29.7(@babel/core@7.29.7(supports-color@8.1.1)) + '@babel/plugin-transform-unicode-escapes': 7.29.7(@babel/core@7.29.7(supports-color@8.1.1)) + '@babel/plugin-transform-unicode-property-regex': 7.29.7(@babel/core@7.29.7(supports-color@8.1.1)) + '@babel/plugin-transform-unicode-regex': 7.29.7(@babel/core@7.29.7(supports-color@8.1.1)) + '@babel/plugin-transform-unicode-sets-regex': 7.29.7(@babel/core@7.29.7(supports-color@8.1.1)) + '@babel/preset-modules': 0.1.6-no-external-plugins(@babel/core@7.29.7(supports-color@8.1.1)) + babel-plugin-polyfill-corejs2: 0.4.17(@babel/core@7.29.7(supports-color@8.1.1))(supports-color@8.1.1) + babel-plugin-polyfill-corejs3: 0.14.2(@babel/core@7.29.7(supports-color@8.1.1))(supports-color@8.1.1) + babel-plugin-polyfill-regenerator: 0.6.8(@babel/core@7.29.7(supports-color@8.1.1))(supports-color@8.1.1) core-js-compat: 3.49.0 semver: 6.3.1 transitivePeerDependencies: - supports-color - '@babel/preset-modules@0.1.6-no-external-plugins(@babel/core@7.29.7)': + '@babel/preset-modules@0.1.6-no-external-plugins(@babel/core@7.29.7(supports-color@8.1.1))': dependencies: - '@babel/core': 7.29.7 + '@babel/core': 7.29.7(supports-color@8.1.1) '@babel/helper-plugin-utils': 7.29.7 '@babel/types': 7.29.7 esutils: 2.0.3 - '@babel/preset-react@7.29.7(@babel/core@7.29.7)': + '@babel/preset-react@7.29.7(@babel/core@7.29.7(supports-color@8.1.1))(supports-color@8.1.1)': dependencies: - '@babel/core': 7.29.7 + '@babel/core': 7.29.7(supports-color@8.1.1) '@babel/helper-plugin-utils': 7.29.7 '@babel/helper-validator-option': 7.29.7 - '@babel/plugin-transform-react-display-name': 7.29.7(@babel/core@7.29.7) - '@babel/plugin-transform-react-jsx': 7.29.7(@babel/core@7.29.7) - '@babel/plugin-transform-react-jsx-development': 7.29.7(@babel/core@7.29.7) - '@babel/plugin-transform-react-pure-annotations': 7.29.7(@babel/core@7.29.7) + '@babel/plugin-transform-react-display-name': 7.29.7(@babel/core@7.29.7(supports-color@8.1.1)) + '@babel/plugin-transform-react-jsx': 7.29.7(@babel/core@7.29.7(supports-color@8.1.1))(supports-color@8.1.1) + '@babel/plugin-transform-react-jsx-development': 7.29.7(@babel/core@7.29.7(supports-color@8.1.1))(supports-color@8.1.1) + '@babel/plugin-transform-react-pure-annotations': 7.29.7(@babel/core@7.29.7(supports-color@8.1.1)) transitivePeerDependencies: - supports-color - '@babel/preset-typescript@7.29.7(@babel/core@7.29.7)': + '@babel/preset-typescript@7.29.7(@babel/core@7.29.7(supports-color@8.1.1))(supports-color@8.1.1)': dependencies: - '@babel/core': 7.29.7 + '@babel/core': 7.29.7(supports-color@8.1.1) '@babel/helper-plugin-utils': 7.29.7 '@babel/helper-validator-option': 7.29.7 - '@babel/plugin-syntax-jsx': 7.29.7(@babel/core@7.29.7) - '@babel/plugin-transform-modules-commonjs': 7.29.7(@babel/core@7.29.7) - '@babel/plugin-transform-typescript': 7.29.7(@babel/core@7.29.7) + '@babel/plugin-syntax-jsx': 7.29.7(@babel/core@7.29.7(supports-color@8.1.1)) + '@babel/plugin-transform-modules-commonjs': 7.29.7(@babel/core@7.29.7(supports-color@8.1.1))(supports-color@8.1.1) + '@babel/plugin-transform-typescript': 7.29.7(@babel/core@7.29.7(supports-color@8.1.1))(supports-color@8.1.1) transitivePeerDependencies: - supports-color @@ -7320,7 +7249,7 @@ snapshots: '@babel/parser': 7.29.7 '@babel/types': 7.29.7 - '@babel/traverse@7.29.7': + '@babel/traverse@7.29.7(supports-color@8.1.1)': dependencies: '@babel/code-frame': 7.29.7 '@babel/generator': 7.29.7 @@ -7328,7 +7257,7 @@ snapshots: '@babel/parser': 7.29.7 '@babel/template': 7.29.7 '@babel/types': 7.29.7 - debug: 4.4.3 + debug: 4.4.3(supports-color@8.1.1) transitivePeerDependencies: - supports-color @@ -7339,24 +7268,35 @@ snapshots: '@bcoe/v8-coverage@0.2.3': {} + '@cfaester/enzyme-adapter-react-18@0.8.0(enzyme@3.11.0)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)': + dependencies: + enzyme: 3.11.0 + enzyme-shallow-equal: 1.0.7 + function.prototype.name: 1.1.8 + has: 1.0.4 + react: 18.3.1 + react-dom: 18.3.1(react@18.3.1) + react-is: 18.3.1 + react-shallow-renderer: 16.15.0(react@18.3.1) + '@codemirror/autocomplete@6.20.3': dependencies: '@codemirror/language': 6.12.4 '@codemirror/state': 6.7.1 - '@codemirror/view': 6.43.6 + '@codemirror/view': 6.43.8 '@lezer/common': 1.5.2 '@codemirror/commands@6.10.4': dependencies: '@codemirror/language': 6.12.4 '@codemirror/state': 6.7.1 - '@codemirror/view': 6.43.6 + '@codemirror/view': 6.43.8 '@lezer/common': 1.5.2 '@codemirror/language@6.12.4': dependencies: '@codemirror/state': 6.7.1 - '@codemirror/view': 6.43.6 + '@codemirror/view': 6.43.8 '@lezer/common': 1.5.2 '@lezer/highlight': 1.2.3 '@lezer/lr': 1.4.10 @@ -7365,23 +7305,23 @@ snapshots: '@codemirror/lint@6.9.7': dependencies: '@codemirror/state': 6.7.1 - '@codemirror/view': 6.43.6 + '@codemirror/view': 6.43.8 crelt: 1.0.6 '@codemirror/search@6.7.1': dependencies: '@codemirror/state': 6.7.1 - '@codemirror/view': 6.43.6 + '@codemirror/view': 6.43.8 crelt: 1.0.6 '@codemirror/state@6.7.1': dependencies: '@marijn/find-cluster-break': 1.0.2 - '@codemirror/view@6.43.6': + '@codemirror/view@6.43.8': dependencies: '@codemirror/state': 6.7.1 - crelt: 1.0.6 + crelt: 1.0.7 style-mod: 4.1.3 w3c-keyname: 2.2.8 @@ -7465,17 +7405,17 @@ snapshots: dependencies: postcss-selector-parser: 6.1.2 - '@eslint-community/eslint-utils@4.9.1(eslint@8.57.1)': + '@eslint-community/eslint-utils@4.9.1(eslint@8.57.1(supports-color@8.1.1))': dependencies: - eslint: 8.57.1 + eslint: 8.57.1(supports-color@8.1.1) eslint-visitor-keys: 3.4.3 '@eslint-community/regexpp@4.12.2': {} - '@eslint/eslintrc@2.1.4': + '@eslint/eslintrc@2.1.4(supports-color@8.1.1)': dependencies: ajv: 6.15.0 - debug: 4.4.3 + debug: 4.4.3(supports-color@8.1.1) espree: 9.6.1 globals: 13.24.0 ignore: 5.3.2 @@ -7504,16 +7444,16 @@ snapshots: dependencies: '@fortawesome/fontawesome-common-types': 6.7.2 - '@fortawesome/react-fontawesome@0.2.6(@fortawesome/fontawesome-svg-core@6.7.2)(react@17.0.2)': + '@fortawesome/react-fontawesome@0.2.6(@fortawesome/fontawesome-svg-core@6.7.2)(react@18.3.1)': dependencies: '@fortawesome/fontawesome-svg-core': 6.7.2 prop-types: 15.8.1 - react: 17.0.2 + react: 18.3.1 - '@humanwhocodes/config-array@0.13.0': + '@humanwhocodes/config-array@0.13.0(supports-color@8.1.1)': dependencies: '@humanwhocodes/object-schema': 2.0.3 - debug: 4.4.3 + debug: 4.4.3(supports-color@8.1.1) minimatch: 3.1.5 transitivePeerDependencies: - supports-color @@ -7522,11 +7462,11 @@ snapshots: '@humanwhocodes/object-schema@2.0.3': {} - '@hypnosphi/create-react-context@0.3.1(prop-types@15.8.1)(react@17.0.2)': + '@hypnosphi/create-react-context@0.3.1(prop-types@15.8.1)(react@18.3.1)': dependencies: gud: 1.0.0 prop-types: 15.8.1 - react: 17.0.2 + react: 18.3.1 warning: 4.0.3 '@istanbuljs/load-nyc-config@1.1.0': @@ -7557,12 +7497,12 @@ snapshots: jest-util: 28.1.3 slash: 3.0.0 - '@jest/core@27.5.1': + '@jest/core@27.5.1(supports-color@8.1.1)': dependencies: '@jest/console': 27.5.1 - '@jest/reporters': 27.5.1 + '@jest/reporters': 27.5.1(supports-color@8.1.1) '@jest/test-result': 27.5.1 - '@jest/transform': 27.5.1 + '@jest/transform': 27.5.1(supports-color@8.1.1) '@jest/types': 27.5.1 '@types/node': 22.20.1 ansi-escapes: 4.3.2 @@ -7571,15 +7511,15 @@ snapshots: exit: 0.1.2 graceful-fs: 4.2.11 jest-changed-files: 27.5.1 - jest-config: 27.5.1 + jest-config: 27.5.1(supports-color@8.1.1) jest-haste-map: 27.5.1 jest-message-util: 27.5.1 jest-regex-util: 27.5.1 jest-resolve: 27.5.1 - jest-resolve-dependencies: 27.5.1 - jest-runner: 27.5.1 - jest-runtime: 27.5.1 - jest-snapshot: 27.5.1 + jest-resolve-dependencies: 27.5.1(supports-color@8.1.1) + jest-runner: 27.5.1(supports-color@8.1.1) + jest-runtime: 27.5.1(supports-color@8.1.1) + jest-snapshot: 27.5.1(supports-color@8.1.1) jest-util: 27.5.1 jest-validate: 27.5.1 jest-watcher: 27.5.1 @@ -7620,12 +7560,12 @@ snapshots: '@jest/types': 27.5.1 expect: 27.5.1 - '@jest/reporters@27.5.1': + '@jest/reporters@27.5.1(supports-color@8.1.1)': dependencies: '@bcoe/v8-coverage': 0.2.3 '@jest/console': 27.5.1 '@jest/test-result': 27.5.1 - '@jest/transform': 27.5.1 + '@jest/transform': 27.5.1(supports-color@8.1.1) '@jest/types': 27.5.1 '@types/node': 22.20.1 chalk: 4.1.2 @@ -7634,9 +7574,9 @@ snapshots: glob: 7.2.3 graceful-fs: 4.2.11 istanbul-lib-coverage: 3.2.2 - istanbul-lib-instrument: 5.2.1 + istanbul-lib-instrument: 5.2.1(supports-color@8.1.1) istanbul-lib-report: 3.0.1 - istanbul-lib-source-maps: 4.0.1 + istanbul-lib-source-maps: 4.0.1(supports-color@8.1.1) istanbul-reports: 3.2.0 jest-haste-map: 27.5.1 jest-resolve: 27.5.1 @@ -7678,20 +7618,20 @@ snapshots: '@types/istanbul-lib-coverage': 2.0.6 collect-v8-coverage: 1.0.3 - '@jest/test-sequencer@27.5.1': + '@jest/test-sequencer@27.5.1(supports-color@8.1.1)': dependencies: '@jest/test-result': 27.5.1 graceful-fs: 4.2.11 jest-haste-map: 27.5.1 - jest-runtime: 27.5.1 + jest-runtime: 27.5.1(supports-color@8.1.1) transitivePeerDependencies: - supports-color - '@jest/transform@27.5.1': + '@jest/transform@27.5.1(supports-color@8.1.1)': dependencies: - '@babel/core': 7.29.7 + '@babel/core': 7.29.7(supports-color@8.1.1) '@jest/types': 27.5.1 - babel-plugin-istanbul: 6.1.1 + babel-plugin-istanbul: 6.1.1(supports-color@8.1.1) chalk: 4.1.2 convert-source-map: 1.9.0 fast-json-stable-stringify: 2.1.0 @@ -7856,7 +7796,7 @@ snapshots: '@pkgr/core@0.3.6': {} - '@pmmmwh/react-refresh-webpack-plugin@0.5.17(react-refresh@0.11.0)(type-fest@4.41.0)(webpack-dev-server@4.15.2(webpack@5.107.1(postcss@8.5.15)))(webpack@5.107.1(postcss@8.5.15))': + '@pmmmwh/react-refresh-webpack-plugin@0.5.17(react-refresh@0.11.0)(type-fest@4.41.0)(webpack-dev-server@4.15.2(debug@4.4.3(supports-color@8.1.1))(supports-color@8.1.1)(webpack@5.107.1(clean-css@5.3.3)(cssnano@5.1.15(postcss@8.5.15))(csso@4.2.0)(html-minifier-terser@6.1.0)(postcss@8.5.15)(uglify-js@3.19.3)))(webpack@5.107.1(clean-css@5.3.3)(cssnano@5.1.15(postcss@8.5.15))(csso@4.2.0)(html-minifier-terser@6.1.0)(postcss@8.5.15)(uglify-js@3.19.3))': dependencies: ansi-html: 0.0.9 core-js-pure: 3.49.0 @@ -7866,15 +7806,15 @@ snapshots: react-refresh: 0.11.0 schema-utils: 4.3.3 source-map: 0.7.6 - webpack: 5.107.1(postcss@8.5.15) + webpack: 5.107.1(clean-css@5.3.3)(cssnano@5.1.15(postcss@8.5.15))(csso@4.2.0)(html-minifier-terser@6.1.0)(postcss@8.5.15)(uglify-js@3.19.3) optionalDependencies: type-fest: 4.41.0 - webpack-dev-server: 4.15.2(webpack@5.107.1(postcss@8.5.15)) + webpack-dev-server: 4.15.2(debug@4.4.3(supports-color@8.1.1))(supports-color@8.1.1)(webpack@5.107.1(clean-css@5.3.3)(cssnano@5.1.15(postcss@8.5.15))(csso@4.2.0)(html-minifier-terser@6.1.0)(postcss@8.5.15)(uglify-js@3.19.3)) - '@rollup/plugin-babel@5.3.1(@babel/core@7.29.7)(@types/babel__core@7.20.5)(rollup@2.80.0)': + '@rollup/plugin-babel@5.3.1(@babel/core@7.29.7(supports-color@8.1.1))(@types/babel__core@7.20.5)(rollup@2.80.0)(supports-color@8.1.1)': dependencies: - '@babel/core': 7.29.7 - '@babel/helper-module-imports': 7.29.7 + '@babel/core': 7.29.7(supports-color@8.1.1) + '@babel/helper-module-imports': 7.29.7(supports-color@8.1.1) '@rollup/pluginutils': 3.1.0(rollup@2.80.0) rollup: 2.80.0 optionalDependencies: @@ -7972,9 +7912,9 @@ snapshots: '@svgr/babel-plugin-transform-react-native-svg': 5.4.0 '@svgr/babel-plugin-transform-svg-component': 5.5.0 - '@svgr/core@5.5.0': + '@svgr/core@5.5.0(supports-color@8.1.1)': dependencies: - '@svgr/plugin-jsx': 5.5.0 + '@svgr/plugin-jsx': 5.5.0(supports-color@8.1.1) camelcase: 6.3.0 cosmiconfig: 7.1.0 transitivePeerDependencies: @@ -7984,9 +7924,9 @@ snapshots: dependencies: '@babel/types': 7.29.7 - '@svgr/plugin-jsx@5.5.0': + '@svgr/plugin-jsx@5.5.0(supports-color@8.1.1)': dependencies: - '@babel/core': 7.29.7 + '@babel/core': 7.29.7(supports-color@8.1.1) '@svgr/babel-preset': 5.5.0 '@svgr/hast-util-to-babel-ast': 5.5.0 svg-parser: 2.0.4 @@ -7999,31 +7939,44 @@ snapshots: deepmerge: 4.3.1 svgo: 1.3.2 - '@svgr/webpack@5.5.0': + '@svgr/webpack@5.5.0(supports-color@8.1.1)': dependencies: - '@babel/core': 7.29.7 - '@babel/plugin-transform-react-constant-elements': 7.29.7(@babel/core@7.29.7) - '@babel/preset-env': 7.29.7(@babel/core@7.29.7) - '@babel/preset-react': 7.29.7(@babel/core@7.29.7) - '@svgr/core': 5.5.0 - '@svgr/plugin-jsx': 5.5.0 + '@babel/core': 7.29.7(supports-color@8.1.1) + '@babel/plugin-transform-react-constant-elements': 7.29.7(@babel/core@7.29.7(supports-color@8.1.1)) + '@babel/preset-env': 7.29.7(@babel/core@7.29.7(supports-color@8.1.1))(supports-color@8.1.1) + '@babel/preset-react': 7.29.7(@babel/core@7.29.7(supports-color@8.1.1))(supports-color@8.1.1) + '@svgr/core': 5.5.0(supports-color@8.1.1) + '@svgr/plugin-jsx': 5.5.0(supports-color@8.1.1) '@svgr/plugin-svgo': 5.5.0 loader-utils: 2.0.4 transitivePeerDependencies: - supports-color - '@testing-library/react-hooks@8.0.1(@types/react@17.0.93)(react-dom@17.0.2(react@17.0.2))(react-test-renderer@17.0.2(react@17.0.2))(react@17.0.2)': + '@testing-library/dom@10.4.1': + dependencies: + '@babel/code-frame': 7.29.7 + '@babel/runtime': 7.29.7 + '@types/aria-query': 5.0.4 + aria-query: 5.3.0 + dom-accessibility-api: 0.5.16 + lz-string: 1.5.0 + picocolors: 1.1.1 + pretty-format: 27.5.1 + + '@testing-library/react@16.3.2(@testing-library/dom@10.4.1)(@types/react-dom@18.3.7(@types/react@18.3.31))(@types/react@18.3.31)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)': dependencies: '@babel/runtime': 7.29.7 - react: 17.0.2 - react-error-boundary: 3.1.4(react@17.0.2) + '@testing-library/dom': 10.4.1 + react: 18.3.1 + react-dom: 18.3.1(react@18.3.1) optionalDependencies: - '@types/react': 17.0.93 - react-dom: 17.0.2(react@17.0.2) - react-test-renderer: 17.0.2(react@17.0.2) + '@types/react': 18.3.31 + '@types/react-dom': 18.3.7(@types/react@18.3.31) '@tootallnate/once@1.1.2': {} + '@types/aria-query@5.0.4': {} + '@types/babel__core@7.20.5': dependencies: '@babel/parser': 7.29.7 @@ -8110,8 +8063,6 @@ snapshots: dependencies: '@types/node': 22.20.1 - '@types/history@4.7.11': {} - '@types/html-minifier-terser@6.1.0': {} '@types/http-errors@2.0.5': {} @@ -8167,22 +8118,11 @@ snapshots: '@types/react-copy-to-clipboard@5.0.7': dependencies: - '@types/react': 17.0.93 + '@types/react': 18.3.31 - '@types/react-dom@17.0.26(@types/react@17.0.93)': + '@types/react-dom@18.3.7(@types/react@18.3.31)': dependencies: - '@types/react': 17.0.93 - - '@types/react-router-dom@5.3.3': - dependencies: - '@types/history': 4.7.11 - '@types/react': 17.0.93 - '@types/react-router': 5.1.20 - - '@types/react-router@5.1.20': - dependencies: - '@types/history': 4.7.11 - '@types/react': 17.0.93 + '@types/react': 18.3.31 '@types/react@16.14.70': dependencies: @@ -8190,10 +8130,9 @@ snapshots: '@types/scheduler': 0.16.8 csstype: 3.2.3 - '@types/react@17.0.93': + '@types/react@18.3.31': dependencies: '@types/prop-types': 15.7.15 - '@types/scheduler': 0.16.8 csstype: 3.2.3 '@types/resolve@1.17.1': @@ -8259,15 +8198,15 @@ snapshots: dependencies: '@types/yargs-parser': 21.0.3 - '@typescript-eslint/eslint-plugin@5.62.0(@typescript-eslint/parser@5.62.0(eslint@8.57.1)(typescript@4.9.5))(eslint@8.57.1)(typescript@4.9.5)': + '@typescript-eslint/eslint-plugin@5.62.0(@typescript-eslint/parser@5.62.0(eslint@8.57.1(supports-color@8.1.1))(supports-color@8.1.1)(typescript@4.9.5))(eslint@8.57.1(supports-color@8.1.1))(supports-color@8.1.1)(typescript@4.9.5)': dependencies: '@eslint-community/regexpp': 4.12.2 - '@typescript-eslint/parser': 5.62.0(eslint@8.57.1)(typescript@4.9.5) + '@typescript-eslint/parser': 5.62.0(eslint@8.57.1(supports-color@8.1.1))(supports-color@8.1.1)(typescript@4.9.5) '@typescript-eslint/scope-manager': 5.62.0 - '@typescript-eslint/type-utils': 5.62.0(eslint@8.57.1)(typescript@4.9.5) - '@typescript-eslint/utils': 5.62.0(eslint@8.57.1)(typescript@4.9.5) - debug: 4.4.3 - eslint: 8.57.1 + '@typescript-eslint/type-utils': 5.62.0(eslint@8.57.1(supports-color@8.1.1))(supports-color@8.1.1)(typescript@4.9.5) + '@typescript-eslint/utils': 5.62.0(eslint@8.57.1(supports-color@8.1.1))(supports-color@8.1.1)(typescript@4.9.5) + debug: 4.4.3(supports-color@8.1.1) + eslint: 8.57.1(supports-color@8.1.1) graphemer: 1.4.0 ignore: 5.3.2 natural-compare-lite: 1.4.0 @@ -8278,21 +8217,21 @@ snapshots: transitivePeerDependencies: - supports-color - '@typescript-eslint/experimental-utils@5.62.0(eslint@8.57.1)(typescript@4.9.5)': + '@typescript-eslint/experimental-utils@5.62.0(eslint@8.57.1(supports-color@8.1.1))(supports-color@8.1.1)(typescript@4.9.5)': dependencies: - '@typescript-eslint/utils': 5.62.0(eslint@8.57.1)(typescript@4.9.5) - eslint: 8.57.1 + '@typescript-eslint/utils': 5.62.0(eslint@8.57.1(supports-color@8.1.1))(supports-color@8.1.1)(typescript@4.9.5) + eslint: 8.57.1(supports-color@8.1.1) transitivePeerDependencies: - supports-color - typescript - '@typescript-eslint/parser@5.62.0(eslint@8.57.1)(typescript@4.9.5)': + '@typescript-eslint/parser@5.62.0(eslint@8.57.1(supports-color@8.1.1))(supports-color@8.1.1)(typescript@4.9.5)': dependencies: '@typescript-eslint/scope-manager': 5.62.0 '@typescript-eslint/types': 5.62.0 - '@typescript-eslint/typescript-estree': 5.62.0(typescript@4.9.5) - debug: 4.4.3 - eslint: 8.57.1 + '@typescript-eslint/typescript-estree': 5.62.0(supports-color@8.1.1)(typescript@4.9.5) + debug: 4.4.3(supports-color@8.1.1) + eslint: 8.57.1(supports-color@8.1.1) optionalDependencies: typescript: 4.9.5 transitivePeerDependencies: @@ -8303,12 +8242,12 @@ snapshots: '@typescript-eslint/types': 5.62.0 '@typescript-eslint/visitor-keys': 5.62.0 - '@typescript-eslint/type-utils@5.62.0(eslint@8.57.1)(typescript@4.9.5)': + '@typescript-eslint/type-utils@5.62.0(eslint@8.57.1(supports-color@8.1.1))(supports-color@8.1.1)(typescript@4.9.5)': dependencies: - '@typescript-eslint/typescript-estree': 5.62.0(typescript@4.9.5) - '@typescript-eslint/utils': 5.62.0(eslint@8.57.1)(typescript@4.9.5) - debug: 4.4.3 - eslint: 8.57.1 + '@typescript-eslint/typescript-estree': 5.62.0(supports-color@8.1.1)(typescript@4.9.5) + '@typescript-eslint/utils': 5.62.0(eslint@8.57.1(supports-color@8.1.1))(supports-color@8.1.1)(typescript@4.9.5) + debug: 4.4.3(supports-color@8.1.1) + eslint: 8.57.1(supports-color@8.1.1) tsutils: 3.21.0(typescript@4.9.5) optionalDependencies: typescript: 4.9.5 @@ -8317,11 +8256,11 @@ snapshots: '@typescript-eslint/types@5.62.0': {} - '@typescript-eslint/typescript-estree@5.62.0(typescript@4.9.5)': + '@typescript-eslint/typescript-estree@5.62.0(supports-color@8.1.1)(typescript@4.9.5)': dependencies: '@typescript-eslint/types': 5.62.0 '@typescript-eslint/visitor-keys': 5.62.0 - debug: 4.4.3 + debug: 4.4.3(supports-color@8.1.1) globby: 11.1.0 is-glob: 4.0.3 semver: 7.8.5 @@ -8331,15 +8270,15 @@ snapshots: transitivePeerDependencies: - supports-color - '@typescript-eslint/utils@5.62.0(eslint@8.57.1)(typescript@4.9.5)': + '@typescript-eslint/utils@5.62.0(eslint@8.57.1(supports-color@8.1.1))(supports-color@8.1.1)(typescript@4.9.5)': dependencies: - '@eslint-community/eslint-utils': 4.9.1(eslint@8.57.1) + '@eslint-community/eslint-utils': 4.9.1(eslint@8.57.1(supports-color@8.1.1)) '@types/json-schema': 7.0.15 '@types/semver': 7.7.1 '@typescript-eslint/scope-manager': 5.62.0 '@typescript-eslint/types': 5.62.0 - '@typescript-eslint/typescript-estree': 5.62.0(typescript@4.9.5) - eslint: 8.57.1 + '@typescript-eslint/typescript-estree': 5.62.0(supports-color@8.1.1)(typescript@4.9.5) + eslint: 8.57.1(supports-color@8.1.1) eslint-scope: 5.1.1 semver: 7.8.5 transitivePeerDependencies: @@ -8429,26 +8368,6 @@ snapshots: '@webassemblyjs/ast': 1.14.1 '@xtuc/long': 4.2.2 - '@wojtekmaj/enzyme-adapter-react-17@0.8.0(enzyme@3.11.0)(react-dom@17.0.2(react@17.0.2))(react@17.0.2)': - dependencies: - '@wojtekmaj/enzyme-adapter-utils': 0.2.0(react@17.0.2) - enzyme: 3.11.0 - enzyme-shallow-equal: 1.0.7 - has: 1.0.4 - prop-types: 15.8.1 - react: 17.0.2 - react-dom: 17.0.2(react@17.0.2) - react-is: 17.0.2 - react-test-renderer: 17.0.2(react@17.0.2) - - '@wojtekmaj/enzyme-adapter-utils@0.2.0(react@17.0.2)': - dependencies: - function.prototype.name: 1.1.8 - has: 1.0.4 - object.fromentries: 2.0.8 - prop-types: 15.8.1 - react: 17.0.2 - '@xtuc/ieee754@1.2.0': {} '@xtuc/long@4.2.2': {} @@ -8486,9 +8405,9 @@ snapshots: loader-utils: 2.0.4 regex-parser: 2.3.1 - agent-base@6.0.2: + agent-base@6.0.2(supports-color@8.1.1): dependencies: - debug: 4.4.3 + debug: 4.4.3(supports-color@8.1.1) transitivePeerDependencies: - supports-color @@ -8556,6 +8475,10 @@ snapshots: argparse@2.0.1: {} + aria-query@5.3.0: + dependencies: + dequal: 2.0.3 + aria-query@5.3.2: {} array-buffer-byte-length@1.0.2: @@ -8678,35 +8601,35 @@ snapshots: axobject-query@4.1.0: {} - babel-jest@27.5.1(@babel/core@7.29.7): + babel-jest@27.5.1(@babel/core@7.29.7(supports-color@8.1.1))(supports-color@8.1.1): dependencies: - '@babel/core': 7.29.7 - '@jest/transform': 27.5.1 + '@babel/core': 7.29.7(supports-color@8.1.1) + '@jest/transform': 27.5.1(supports-color@8.1.1) '@jest/types': 27.5.1 '@types/babel__core': 7.20.5 - babel-plugin-istanbul: 6.1.1 - babel-preset-jest: 27.5.1(@babel/core@7.29.7) + babel-plugin-istanbul: 6.1.1(supports-color@8.1.1) + babel-preset-jest: 27.5.1(@babel/core@7.29.7(supports-color@8.1.1)) chalk: 4.1.2 graceful-fs: 4.2.11 slash: 3.0.0 transitivePeerDependencies: - supports-color - babel-loader@8.4.1(@babel/core@7.29.7)(webpack@5.107.1(postcss@8.5.15)): + babel-loader@8.4.1(@babel/core@7.29.7(supports-color@8.1.1))(webpack@5.107.1(clean-css@5.3.3)(cssnano@5.1.15(postcss@8.5.15))(csso@4.2.0)(html-minifier-terser@6.1.0)(postcss@8.5.15)(uglify-js@3.19.3)): dependencies: - '@babel/core': 7.29.7 + '@babel/core': 7.29.7(supports-color@8.1.1) find-cache-dir: 3.3.2 loader-utils: 2.0.4 make-dir: 3.1.0 schema-utils: 2.7.1 - webpack: 5.107.1(postcss@8.5.15) + webpack: 5.107.1(clean-css@5.3.3)(cssnano@5.1.15(postcss@8.5.15))(csso@4.2.0)(html-minifier-terser@6.1.0)(postcss@8.5.15)(uglify-js@3.19.3) - babel-plugin-istanbul@6.1.1: + babel-plugin-istanbul@6.1.1(supports-color@8.1.1): dependencies: '@babel/helper-plugin-utils': 7.29.7 '@istanbuljs/load-nyc-config': 1.1.0 '@istanbuljs/schema': 0.1.6 - istanbul-lib-instrument: 5.2.1 + istanbul-lib-instrument: 5.2.1(supports-color@8.1.1) test-exclude: 6.0.0 transitivePeerDependencies: - supports-color @@ -8724,85 +8647,85 @@ snapshots: cosmiconfig: 7.1.0 resolve: 1.22.12 - babel-plugin-named-asset-import@0.3.8(@babel/core@7.29.7): + babel-plugin-named-asset-import@0.3.8(@babel/core@7.29.7(supports-color@8.1.1)): dependencies: - '@babel/core': 7.29.7 + '@babel/core': 7.29.7(supports-color@8.1.1) - babel-plugin-polyfill-corejs2@0.4.17(@babel/core@7.29.7): + babel-plugin-polyfill-corejs2@0.4.17(@babel/core@7.29.7(supports-color@8.1.1))(supports-color@8.1.1): dependencies: '@babel/compat-data': 7.29.7 - '@babel/core': 7.29.7 - '@babel/helper-define-polyfill-provider': 0.6.8(@babel/core@7.29.7) + '@babel/core': 7.29.7(supports-color@8.1.1) + '@babel/helper-define-polyfill-provider': 0.6.8(@babel/core@7.29.7(supports-color@8.1.1))(supports-color@8.1.1) semver: 6.3.1 transitivePeerDependencies: - supports-color - babel-plugin-polyfill-corejs3@0.13.0(@babel/core@7.29.7): + babel-plugin-polyfill-corejs3@0.13.0(@babel/core@7.29.7(supports-color@8.1.1))(supports-color@8.1.1): dependencies: - '@babel/core': 7.29.7 - '@babel/helper-define-polyfill-provider': 0.6.8(@babel/core@7.29.7) + '@babel/core': 7.29.7(supports-color@8.1.1) + '@babel/helper-define-polyfill-provider': 0.6.8(@babel/core@7.29.7(supports-color@8.1.1))(supports-color@8.1.1) core-js-compat: 3.49.0 transitivePeerDependencies: - supports-color - babel-plugin-polyfill-corejs3@0.14.2(@babel/core@7.29.7): + babel-plugin-polyfill-corejs3@0.14.2(@babel/core@7.29.7(supports-color@8.1.1))(supports-color@8.1.1): dependencies: - '@babel/core': 7.29.7 - '@babel/helper-define-polyfill-provider': 0.6.8(@babel/core@7.29.7) + '@babel/core': 7.29.7(supports-color@8.1.1) + '@babel/helper-define-polyfill-provider': 0.6.8(@babel/core@7.29.7(supports-color@8.1.1))(supports-color@8.1.1) core-js-compat: 3.49.0 transitivePeerDependencies: - supports-color - babel-plugin-polyfill-regenerator@0.6.8(@babel/core@7.29.7): + babel-plugin-polyfill-regenerator@0.6.8(@babel/core@7.29.7(supports-color@8.1.1))(supports-color@8.1.1): dependencies: - '@babel/core': 7.29.7 - '@babel/helper-define-polyfill-provider': 0.6.8(@babel/core@7.29.7) + '@babel/core': 7.29.7(supports-color@8.1.1) + '@babel/helper-define-polyfill-provider': 0.6.8(@babel/core@7.29.7(supports-color@8.1.1))(supports-color@8.1.1) transitivePeerDependencies: - supports-color babel-plugin-transform-react-remove-prop-types@0.4.24: {} - babel-preset-current-node-syntax@1.2.0(@babel/core@7.29.7): - dependencies: - '@babel/core': 7.29.7 - '@babel/plugin-syntax-async-generators': 7.8.4(@babel/core@7.29.7) - '@babel/plugin-syntax-bigint': 7.8.3(@babel/core@7.29.7) - '@babel/plugin-syntax-class-properties': 7.12.13(@babel/core@7.29.7) - '@babel/plugin-syntax-class-static-block': 7.14.5(@babel/core@7.29.7) - '@babel/plugin-syntax-import-attributes': 7.29.7(@babel/core@7.29.7) - '@babel/plugin-syntax-import-meta': 7.10.4(@babel/core@7.29.7) - '@babel/plugin-syntax-json-strings': 7.8.3(@babel/core@7.29.7) - '@babel/plugin-syntax-logical-assignment-operators': 7.10.4(@babel/core@7.29.7) - '@babel/plugin-syntax-nullish-coalescing-operator': 7.8.3(@babel/core@7.29.7) - '@babel/plugin-syntax-numeric-separator': 7.10.4(@babel/core@7.29.7) - '@babel/plugin-syntax-object-rest-spread': 7.8.3(@babel/core@7.29.7) - '@babel/plugin-syntax-optional-catch-binding': 7.8.3(@babel/core@7.29.7) - '@babel/plugin-syntax-optional-chaining': 7.8.3(@babel/core@7.29.7) - '@babel/plugin-syntax-private-property-in-object': 7.14.5(@babel/core@7.29.7) - '@babel/plugin-syntax-top-level-await': 7.14.5(@babel/core@7.29.7) - - babel-preset-jest@27.5.1(@babel/core@7.29.7): - dependencies: - '@babel/core': 7.29.7 + babel-preset-current-node-syntax@1.2.0(@babel/core@7.29.7(supports-color@8.1.1)): + dependencies: + '@babel/core': 7.29.7(supports-color@8.1.1) + '@babel/plugin-syntax-async-generators': 7.8.4(@babel/core@7.29.7(supports-color@8.1.1)) + '@babel/plugin-syntax-bigint': 7.8.3(@babel/core@7.29.7(supports-color@8.1.1)) + '@babel/plugin-syntax-class-properties': 7.12.13(@babel/core@7.29.7(supports-color@8.1.1)) + '@babel/plugin-syntax-class-static-block': 7.14.5(@babel/core@7.29.7(supports-color@8.1.1)) + '@babel/plugin-syntax-import-attributes': 7.29.7(@babel/core@7.29.7(supports-color@8.1.1)) + '@babel/plugin-syntax-import-meta': 7.10.4(@babel/core@7.29.7(supports-color@8.1.1)) + '@babel/plugin-syntax-json-strings': 7.8.3(@babel/core@7.29.7(supports-color@8.1.1)) + '@babel/plugin-syntax-logical-assignment-operators': 7.10.4(@babel/core@7.29.7(supports-color@8.1.1)) + '@babel/plugin-syntax-nullish-coalescing-operator': 7.8.3(@babel/core@7.29.7(supports-color@8.1.1)) + '@babel/plugin-syntax-numeric-separator': 7.10.4(@babel/core@7.29.7(supports-color@8.1.1)) + '@babel/plugin-syntax-object-rest-spread': 7.8.3(@babel/core@7.29.7(supports-color@8.1.1)) + '@babel/plugin-syntax-optional-catch-binding': 7.8.3(@babel/core@7.29.7(supports-color@8.1.1)) + '@babel/plugin-syntax-optional-chaining': 7.8.3(@babel/core@7.29.7(supports-color@8.1.1)) + '@babel/plugin-syntax-private-property-in-object': 7.14.5(@babel/core@7.29.7(supports-color@8.1.1)) + '@babel/plugin-syntax-top-level-await': 7.14.5(@babel/core@7.29.7(supports-color@8.1.1)) + + babel-preset-jest@27.5.1(@babel/core@7.29.7(supports-color@8.1.1)): + dependencies: + '@babel/core': 7.29.7(supports-color@8.1.1) babel-plugin-jest-hoist: 27.5.1 - babel-preset-current-node-syntax: 1.2.0(@babel/core@7.29.7) - - babel-preset-react-app@10.1.0: - dependencies: - '@babel/core': 7.29.7 - '@babel/plugin-proposal-class-properties': 7.18.6(@babel/core@7.29.7) - '@babel/plugin-proposal-decorators': 7.29.7(@babel/core@7.29.7) - '@babel/plugin-proposal-nullish-coalescing-operator': 7.18.6(@babel/core@7.29.7) - '@babel/plugin-proposal-numeric-separator': 7.18.6(@babel/core@7.29.7) - '@babel/plugin-proposal-optional-chaining': 7.21.0(@babel/core@7.29.7) - '@babel/plugin-proposal-private-methods': 7.18.6(@babel/core@7.29.7) - '@babel/plugin-proposal-private-property-in-object': 7.21.11(@babel/core@7.29.7) - '@babel/plugin-transform-flow-strip-types': 7.29.7(@babel/core@7.29.7) - '@babel/plugin-transform-react-display-name': 7.29.7(@babel/core@7.29.7) - '@babel/plugin-transform-runtime': 7.29.7(@babel/core@7.29.7) - '@babel/preset-env': 7.29.7(@babel/core@7.29.7) - '@babel/preset-react': 7.29.7(@babel/core@7.29.7) - '@babel/preset-typescript': 7.29.7(@babel/core@7.29.7) + babel-preset-current-node-syntax: 1.2.0(@babel/core@7.29.7(supports-color@8.1.1)) + + babel-preset-react-app@10.1.0(supports-color@8.1.1): + dependencies: + '@babel/core': 7.29.7(supports-color@8.1.1) + '@babel/plugin-proposal-class-properties': 7.18.6(@babel/core@7.29.7(supports-color@8.1.1))(supports-color@8.1.1) + '@babel/plugin-proposal-decorators': 7.29.7(@babel/core@7.29.7(supports-color@8.1.1))(supports-color@8.1.1) + '@babel/plugin-proposal-nullish-coalescing-operator': 7.18.6(@babel/core@7.29.7(supports-color@8.1.1)) + '@babel/plugin-proposal-numeric-separator': 7.18.6(@babel/core@7.29.7(supports-color@8.1.1)) + '@babel/plugin-proposal-optional-chaining': 7.21.0(@babel/core@7.29.7(supports-color@8.1.1))(supports-color@8.1.1) + '@babel/plugin-proposal-private-methods': 7.18.6(@babel/core@7.29.7(supports-color@8.1.1))(supports-color@8.1.1) + '@babel/plugin-proposal-private-property-in-object': 7.21.11(@babel/core@7.29.7(supports-color@8.1.1))(supports-color@8.1.1) + '@babel/plugin-transform-flow-strip-types': 7.29.7(@babel/core@7.29.7(supports-color@8.1.1)) + '@babel/plugin-transform-react-display-name': 7.29.7(@babel/core@7.29.7(supports-color@8.1.1)) + '@babel/plugin-transform-runtime': 7.29.7(@babel/core@7.29.7(supports-color@8.1.1))(supports-color@8.1.1) + '@babel/preset-env': 7.29.7(@babel/core@7.29.7(supports-color@8.1.1))(supports-color@8.1.1) + '@babel/preset-react': 7.29.7(@babel/core@7.29.7(supports-color@8.1.1))(supports-color@8.1.1) + '@babel/preset-typescript': 7.29.7(@babel/core@7.29.7(supports-color@8.1.1))(supports-color@8.1.1) '@babel/runtime': 7.29.7 babel-plugin-macros: 3.1.0 babel-plugin-transform-react-remove-prop-types: 0.4.24 @@ -8829,11 +8752,11 @@ snapshots: bluebird@3.7.2: {} - body-parser@1.20.5: + body-parser@1.20.5(supports-color@8.1.1): dependencies: bytes: 3.1.2 content-type: 1.0.5 - debug: 2.6.9 + debug: 2.6.9(supports-color@8.1.1) depd: 2.0.0 destroy: 1.2.0 http-errors: 2.0.1 @@ -8881,10 +8804,6 @@ snapshots: node-releases: 2.0.47 update-browserslist-db: 1.2.3(browserslist@4.28.2) - bs-logger@0.2.6: - dependencies: - fast-json-stable-stringify: 2.1.0 - bser@2.1.1: dependencies: node-int64: 0.4.0 @@ -8962,19 +8881,15 @@ snapshots: domhandler: 5.0.3 domutils: 3.2.2 - cheerio@1.2.0: + cheerio@1.0.0-rc.12: dependencies: cheerio-select: 2.1.0 dom-serializer: 2.0.0 domhandler: 5.0.3 domutils: 3.2.2 - encoding-sniffer: 0.2.1 - htmlparser2: 10.1.0 + htmlparser2: 8.0.2 parse5: 7.3.0 parse5-htmlparser2-tree-adapter: 7.1.0 - parse5-parser-stream: 7.1.2 - undici: 7.25.0 - whatwg-mimetype: 4.0.0 chokidar@3.6.0: dependencies: @@ -9056,11 +8971,11 @@ snapshots: dependencies: mime-db: 1.54.0 - compression@1.8.1: + compression@1.8.1(supports-color@8.1.1): dependencies: bytes: 3.1.2 compressible: 2.0.18 - debug: 2.6.9 + debug: 2.6.9(supports-color@8.1.1) negotiator: 0.6.4 on-headers: 1.1.0 safe-buffer: 5.2.1 @@ -9090,6 +9005,8 @@ snapshots: cookie@0.7.2: {} + cookie@1.1.1: {} + copy-to-clipboard@3.3.3: dependencies: toggle-selection: 1.0.6 @@ -9122,6 +9039,8 @@ snapshots: crelt@1.0.6: {} + crelt@1.0.7: {} + cross-fetch@3.2.0: dependencies: node-fetch: 2.7.0 @@ -9150,7 +9069,7 @@ snapshots: postcss: 8.5.15 postcss-selector-parser: 6.1.2 - css-loader@6.11.0(webpack@5.107.1(postcss@8.5.15)): + css-loader@6.11.0(webpack@5.107.1(clean-css@5.3.3)(cssnano@5.1.15(postcss@8.5.15))(csso@4.2.0)(html-minifier-terser@6.1.0)(postcss@8.5.15)(uglify-js@3.19.3)): dependencies: icss-utils: 5.1.0(postcss@8.5.15) postcss: 8.5.15 @@ -9161,9 +9080,9 @@ snapshots: postcss-value-parser: 4.2.0 semver: 7.8.5 optionalDependencies: - webpack: 5.107.1(postcss@8.5.15) + webpack: 5.107.1(clean-css@5.3.3)(cssnano@5.1.15(postcss@8.5.15))(csso@4.2.0)(html-minifier-terser@6.1.0)(postcss@8.5.15)(uglify-js@3.19.3) - css-minimizer-webpack-plugin@3.4.1(webpack@5.107.1(postcss@8.5.15)): + css-minimizer-webpack-plugin@3.4.1(clean-css@5.3.3)(csso@4.2.0)(webpack@5.107.1(clean-css@5.3.3)(cssnano@5.1.15(postcss@8.5.15))(csso@4.2.0)(html-minifier-terser@6.1.0)(postcss@8.5.15)(uglify-js@3.19.3)): dependencies: cssnano: 5.1.15(postcss@8.5.15) jest-worker: 27.5.1 @@ -9171,7 +9090,10 @@ snapshots: schema-utils: 4.3.3 serialize-javascript: 6.0.2 source-map: 0.6.1 - webpack: 5.107.1(postcss@8.5.15) + webpack: 5.107.1(clean-css@5.3.3)(cssnano@5.1.15(postcss@8.5.15))(csso@4.2.0)(html-minifier-terser@6.1.0)(postcss@8.5.15)(uglify-js@3.19.3) + optionalDependencies: + clean-css: 5.3.3 + csso: 4.2.0 css-prefers-color-scheme@6.0.3(postcss@8.5.15): dependencies: @@ -9310,17 +9232,23 @@ snapshots: dayjs@1.11.20: {} - debug@2.6.9: + debug@2.6.9(supports-color@8.1.1): dependencies: ms: 2.0.0 + optionalDependencies: + supports-color: 8.1.1 - debug@3.2.7: + debug@3.2.7(supports-color@8.1.1): dependencies: ms: 2.1.3 + optionalDependencies: + supports-color: 8.1.1 - debug@4.4.3: + debug@4.4.3(supports-color@8.1.1): dependencies: ms: 2.1.3 + optionalDependencies: + supports-color: 8.1.1 decimal.js@10.6.0: {} @@ -9363,6 +9291,8 @@ snapshots: depd@2.0.0: {} + dequal@2.0.3: {} + destroy@1.2.0: {} detect-libc@2.1.2: @@ -9372,10 +9302,10 @@ snapshots: detect-node@2.1.0: {} - detect-port-alt@1.1.6: + detect-port-alt@1.1.6(supports-color@8.1.1): dependencies: address: 1.2.2 - debug: 2.6.9 + debug: 2.6.9(supports-color@8.1.1) transitivePeerDependencies: - supports-color @@ -9407,6 +9337,8 @@ snapshots: dependencies: esutils: 2.0.3 + dom-accessibility-api@0.5.16: {} + dom-converter@0.2.0: dependencies: utila: 0.4.0 @@ -9496,12 +9428,12 @@ snapshots: dotenv@10.0.0: {} - downshift@9.4.0(react@17.0.2): + downshift@9.4.0(react@18.3.1): dependencies: '@babel/runtime': 7.29.7 compute-scroll-into-view: 3.1.1 prop-types: 15.8.1 - react: 17.0.2 + react: 18.3.1 react-is: 18.3.1 tslib: 2.8.1 @@ -9533,11 +9465,6 @@ snapshots: encodeurl@2.0.0: {} - encoding-sniffer@0.2.1: - dependencies: - iconv-lite: 0.6.3 - whatwg-encoding: 3.1.1 - enhanced-resolve@5.22.0: dependencies: graceful-fs: 4.2.11 @@ -9568,7 +9495,7 @@ snapshots: enzyme@3.11.0: dependencies: array.prototype.flat: 1.3.3 - cheerio: 1.2.0 + cheerio: 1.0.0-rc.12 enzyme-shallow-equal: 1.0.7 function.prototype.name: 1.1.8 has: 1.0.4 @@ -9721,27 +9648,27 @@ snapshots: optionalDependencies: source-map: 0.6.1 - eslint-config-prettier@10.1.8(eslint@8.57.1): + eslint-config-prettier@10.1.8(eslint@8.57.1(supports-color@8.1.1)): dependencies: - eslint: 8.57.1 + eslint: 8.57.1(supports-color@8.1.1) - eslint-config-react-app@7.0.1(@babel/plugin-syntax-flow@7.29.7(@babel/core@7.29.7))(@babel/plugin-transform-react-jsx@7.29.7(@babel/core@7.29.7))(eslint@8.57.1)(jest@27.5.1)(typescript@4.9.5): + eslint-config-react-app@7.0.1(@babel/plugin-syntax-flow@7.29.7(@babel/core@7.29.7(supports-color@8.1.1)))(@babel/plugin-transform-react-jsx@7.29.7(@babel/core@7.29.7(supports-color@8.1.1))(supports-color@8.1.1))(eslint@8.57.1(supports-color@8.1.1))(jest@27.5.1(supports-color@8.1.1))(supports-color@8.1.1)(typescript@4.9.5): dependencies: - '@babel/core': 7.29.7 - '@babel/eslint-parser': 7.29.7(@babel/core@7.29.7)(eslint@8.57.1) + '@babel/core': 7.29.7(supports-color@8.1.1) + '@babel/eslint-parser': 7.29.7(@babel/core@7.29.7(supports-color@8.1.1))(eslint@8.57.1(supports-color@8.1.1)) '@rushstack/eslint-patch': 1.16.1 - '@typescript-eslint/eslint-plugin': 5.62.0(@typescript-eslint/parser@5.62.0(eslint@8.57.1)(typescript@4.9.5))(eslint@8.57.1)(typescript@4.9.5) - '@typescript-eslint/parser': 5.62.0(eslint@8.57.1)(typescript@4.9.5) - babel-preset-react-app: 10.1.0 + '@typescript-eslint/eslint-plugin': 5.62.0(@typescript-eslint/parser@5.62.0(eslint@8.57.1(supports-color@8.1.1))(supports-color@8.1.1)(typescript@4.9.5))(eslint@8.57.1(supports-color@8.1.1))(supports-color@8.1.1)(typescript@4.9.5) + '@typescript-eslint/parser': 5.62.0(eslint@8.57.1(supports-color@8.1.1))(supports-color@8.1.1)(typescript@4.9.5) + babel-preset-react-app: 10.1.0(supports-color@8.1.1) confusing-browser-globals: 1.0.11 - eslint: 8.57.1 - eslint-plugin-flowtype: 8.0.3(@babel/plugin-syntax-flow@7.29.7(@babel/core@7.29.7))(@babel/plugin-transform-react-jsx@7.29.7(@babel/core@7.29.7))(eslint@8.57.1) - eslint-plugin-import: 2.32.0(@typescript-eslint/parser@5.62.0(eslint@8.57.1)(typescript@4.9.5))(eslint@8.57.1) - eslint-plugin-jest: 25.7.0(@typescript-eslint/eslint-plugin@5.62.0(@typescript-eslint/parser@5.62.0(eslint@8.57.1)(typescript@4.9.5))(eslint@8.57.1)(typescript@4.9.5))(eslint@8.57.1)(jest@27.5.1)(typescript@4.9.5) - eslint-plugin-jsx-a11y: 6.10.2(eslint@8.57.1) - eslint-plugin-react: 7.37.5(eslint@8.57.1) - eslint-plugin-react-hooks: 4.6.2(eslint@8.57.1) - eslint-plugin-testing-library: 5.11.1(eslint@8.57.1)(typescript@4.9.5) + eslint: 8.57.1(supports-color@8.1.1) + eslint-plugin-flowtype: 8.0.3(@babel/plugin-syntax-flow@7.29.7(@babel/core@7.29.7(supports-color@8.1.1)))(@babel/plugin-transform-react-jsx@7.29.7(@babel/core@7.29.7(supports-color@8.1.1))(supports-color@8.1.1))(eslint@8.57.1(supports-color@8.1.1)) + eslint-plugin-import: 2.32.0(@typescript-eslint/parser@5.62.0(eslint@8.57.1(supports-color@8.1.1))(supports-color@8.1.1)(typescript@4.9.5))(eslint@8.57.1(supports-color@8.1.1))(supports-color@8.1.1) + eslint-plugin-jest: 25.7.0(@typescript-eslint/eslint-plugin@5.62.0(@typescript-eslint/parser@5.62.0(eslint@8.57.1(supports-color@8.1.1))(supports-color@8.1.1)(typescript@4.9.5))(eslint@8.57.1(supports-color@8.1.1))(supports-color@8.1.1)(typescript@4.9.5))(eslint@8.57.1(supports-color@8.1.1))(jest@27.5.1(supports-color@8.1.1))(supports-color@8.1.1)(typescript@4.9.5) + eslint-plugin-jsx-a11y: 6.10.2(eslint@8.57.1(supports-color@8.1.1)) + eslint-plugin-react: 7.37.5(eslint@8.57.1(supports-color@8.1.1)) + eslint-plugin-react-hooks: 4.6.2(eslint@8.57.1(supports-color@8.1.1)) + eslint-plugin-testing-library: 5.11.1(eslint@8.57.1(supports-color@8.1.1))(supports-color@8.1.1)(typescript@4.9.5) optionalDependencies: typescript: 4.9.5 transitivePeerDependencies: @@ -9752,44 +9679,44 @@ snapshots: - jest - supports-color - eslint-import-resolver-node@0.3.10: + eslint-import-resolver-node@0.3.10(supports-color@8.1.1): dependencies: - debug: 3.2.7 + debug: 3.2.7(supports-color@8.1.1) is-core-module: 2.16.2 resolve: 2.0.0-next.7 transitivePeerDependencies: - supports-color - eslint-module-utils@2.12.1(@typescript-eslint/parser@5.62.0(eslint@8.57.1)(typescript@4.9.5))(eslint-import-resolver-node@0.3.10)(eslint@8.57.1): + eslint-module-utils@2.12.1(@typescript-eslint/parser@5.62.0(eslint@8.57.1(supports-color@8.1.1))(supports-color@8.1.1)(typescript@4.9.5))(eslint-import-resolver-node@0.3.10(supports-color@8.1.1))(eslint@8.57.1(supports-color@8.1.1))(supports-color@8.1.1): dependencies: - debug: 3.2.7 + debug: 3.2.7(supports-color@8.1.1) optionalDependencies: - '@typescript-eslint/parser': 5.62.0(eslint@8.57.1)(typescript@4.9.5) - eslint: 8.57.1 - eslint-import-resolver-node: 0.3.10 + '@typescript-eslint/parser': 5.62.0(eslint@8.57.1(supports-color@8.1.1))(supports-color@8.1.1)(typescript@4.9.5) + eslint: 8.57.1(supports-color@8.1.1) + eslint-import-resolver-node: 0.3.10(supports-color@8.1.1) transitivePeerDependencies: - supports-color - eslint-plugin-flowtype@8.0.3(@babel/plugin-syntax-flow@7.29.7(@babel/core@7.29.7))(@babel/plugin-transform-react-jsx@7.29.7(@babel/core@7.29.7))(eslint@8.57.1): + eslint-plugin-flowtype@8.0.3(@babel/plugin-syntax-flow@7.29.7(@babel/core@7.29.7(supports-color@8.1.1)))(@babel/plugin-transform-react-jsx@7.29.7(@babel/core@7.29.7(supports-color@8.1.1))(supports-color@8.1.1))(eslint@8.57.1(supports-color@8.1.1)): dependencies: - '@babel/plugin-syntax-flow': 7.29.7(@babel/core@7.29.7) - '@babel/plugin-transform-react-jsx': 7.29.7(@babel/core@7.29.7) - eslint: 8.57.1 + '@babel/plugin-syntax-flow': 7.29.7(@babel/core@7.29.7(supports-color@8.1.1)) + '@babel/plugin-transform-react-jsx': 7.29.7(@babel/core@7.29.7(supports-color@8.1.1))(supports-color@8.1.1) + eslint: 8.57.1(supports-color@8.1.1) lodash: 4.18.1 string-natural-compare: 3.0.1 - eslint-plugin-import@2.32.0(@typescript-eslint/parser@5.62.0(eslint@8.57.1)(typescript@4.9.5))(eslint@8.57.1): + eslint-plugin-import@2.32.0(@typescript-eslint/parser@5.62.0(eslint@8.57.1(supports-color@8.1.1))(supports-color@8.1.1)(typescript@4.9.5))(eslint@8.57.1(supports-color@8.1.1))(supports-color@8.1.1): dependencies: '@rtsao/scc': 1.1.0 array-includes: 3.1.9 array.prototype.findlastindex: 1.2.6 array.prototype.flat: 1.3.3 array.prototype.flatmap: 1.3.3 - debug: 3.2.7 + debug: 3.2.7(supports-color@8.1.1) doctrine: 2.1.0 - eslint: 8.57.1 - eslint-import-resolver-node: 0.3.10 - eslint-module-utils: 2.12.1(@typescript-eslint/parser@5.62.0(eslint@8.57.1)(typescript@4.9.5))(eslint-import-resolver-node@0.3.10)(eslint@8.57.1) + eslint: 8.57.1(supports-color@8.1.1) + eslint-import-resolver-node: 0.3.10(supports-color@8.1.1) + eslint-module-utils: 2.12.1(@typescript-eslint/parser@5.62.0(eslint@8.57.1(supports-color@8.1.1))(supports-color@8.1.1)(typescript@4.9.5))(eslint-import-resolver-node@0.3.10(supports-color@8.1.1))(eslint@8.57.1(supports-color@8.1.1))(supports-color@8.1.1) hasown: 2.0.4 is-core-module: 2.16.2 is-glob: 4.0.3 @@ -9801,24 +9728,24 @@ snapshots: string.prototype.trimend: 1.0.9 tsconfig-paths: 3.15.0 optionalDependencies: - '@typescript-eslint/parser': 5.62.0(eslint@8.57.1)(typescript@4.9.5) + '@typescript-eslint/parser': 5.62.0(eslint@8.57.1(supports-color@8.1.1))(supports-color@8.1.1)(typescript@4.9.5) transitivePeerDependencies: - eslint-import-resolver-typescript - eslint-import-resolver-webpack - supports-color - eslint-plugin-jest@25.7.0(@typescript-eslint/eslint-plugin@5.62.0(@typescript-eslint/parser@5.62.0(eslint@8.57.1)(typescript@4.9.5))(eslint@8.57.1)(typescript@4.9.5))(eslint@8.57.1)(jest@27.5.1)(typescript@4.9.5): + eslint-plugin-jest@25.7.0(@typescript-eslint/eslint-plugin@5.62.0(@typescript-eslint/parser@5.62.0(eslint@8.57.1(supports-color@8.1.1))(supports-color@8.1.1)(typescript@4.9.5))(eslint@8.57.1(supports-color@8.1.1))(supports-color@8.1.1)(typescript@4.9.5))(eslint@8.57.1(supports-color@8.1.1))(jest@27.5.1(supports-color@8.1.1))(supports-color@8.1.1)(typescript@4.9.5): dependencies: - '@typescript-eslint/experimental-utils': 5.62.0(eslint@8.57.1)(typescript@4.9.5) - eslint: 8.57.1 + '@typescript-eslint/experimental-utils': 5.62.0(eslint@8.57.1(supports-color@8.1.1))(supports-color@8.1.1)(typescript@4.9.5) + eslint: 8.57.1(supports-color@8.1.1) optionalDependencies: - '@typescript-eslint/eslint-plugin': 5.62.0(@typescript-eslint/parser@5.62.0(eslint@8.57.1)(typescript@4.9.5))(eslint@8.57.1)(typescript@4.9.5) - jest: 27.5.1 + '@typescript-eslint/eslint-plugin': 5.62.0(@typescript-eslint/parser@5.62.0(eslint@8.57.1(supports-color@8.1.1))(supports-color@8.1.1)(typescript@4.9.5))(eslint@8.57.1(supports-color@8.1.1))(supports-color@8.1.1)(typescript@4.9.5) + jest: 27.5.1(supports-color@8.1.1) transitivePeerDependencies: - supports-color - typescript - eslint-plugin-jsx-a11y@6.10.2(eslint@8.57.1): + eslint-plugin-jsx-a11y@6.10.2(eslint@8.57.1(supports-color@8.1.1)): dependencies: aria-query: 5.3.2 array-includes: 3.1.9 @@ -9828,7 +9755,7 @@ snapshots: axobject-query: 4.1.0 damerau-levenshtein: 1.0.8 emoji-regex: 9.2.2 - eslint: 8.57.1 + eslint: 8.57.1(supports-color@8.1.1) hasown: 2.0.4 jsx-ast-utils: 3.3.5 language-tags: 1.0.9 @@ -9837,21 +9764,21 @@ snapshots: safe-regex-test: 1.1.0 string.prototype.includes: 2.0.1 - eslint-plugin-prettier@5.5.6(@types/eslint@8.56.12)(eslint-config-prettier@10.1.8(eslint@8.57.1))(eslint@8.57.1)(prettier@3.9.6): + eslint-plugin-prettier@5.5.6(@types/eslint@8.56.12)(eslint-config-prettier@10.1.8(eslint@8.57.1(supports-color@8.1.1)))(eslint@8.57.1(supports-color@8.1.1))(prettier@3.9.6): dependencies: - eslint: 8.57.1 + eslint: 8.57.1(supports-color@8.1.1) prettier: 3.9.6 prettier-linter-helpers: 1.0.1 synckit: 0.11.13 optionalDependencies: '@types/eslint': 8.56.12 - eslint-config-prettier: 10.1.8(eslint@8.57.1) + eslint-config-prettier: 10.1.8(eslint@8.57.1(supports-color@8.1.1)) - eslint-plugin-react-hooks@4.6.2(eslint@8.57.1): + eslint-plugin-react-hooks@4.6.2(eslint@8.57.1(supports-color@8.1.1)): dependencies: - eslint: 8.57.1 + eslint: 8.57.1(supports-color@8.1.1) - eslint-plugin-react@7.37.5(eslint@8.57.1): + eslint-plugin-react@7.37.5(eslint@8.57.1(supports-color@8.1.1)): dependencies: array-includes: 3.1.9 array.prototype.findlast: 1.2.5 @@ -9859,7 +9786,7 @@ snapshots: array.prototype.tosorted: 1.1.4 doctrine: 2.1.0 es-iterator-helpers: 1.3.2 - eslint: 8.57.1 + eslint: 8.57.1(supports-color@8.1.1) estraverse: 5.3.0 hasown: 2.0.4 jsx-ast-utils: 3.3.5 @@ -9873,10 +9800,10 @@ snapshots: string.prototype.matchall: 4.0.12 string.prototype.repeat: 1.0.0 - eslint-plugin-testing-library@5.11.1(eslint@8.57.1)(typescript@4.9.5): + eslint-plugin-testing-library@5.11.1(eslint@8.57.1(supports-color@8.1.1))(supports-color@8.1.1)(typescript@4.9.5): dependencies: - '@typescript-eslint/utils': 5.62.0(eslint@8.57.1)(typescript@4.9.5) - eslint: 8.57.1 + '@typescript-eslint/utils': 5.62.0(eslint@8.57.1(supports-color@8.1.1))(supports-color@8.1.1)(typescript@4.9.5) + eslint: 8.57.1(supports-color@8.1.1) transitivePeerDependencies: - supports-color - typescript @@ -9895,30 +9822,30 @@ snapshots: eslint-visitor-keys@3.4.3: {} - eslint-webpack-plugin@3.2.0(eslint@8.57.1)(webpack@5.107.1(postcss@8.5.15)): + eslint-webpack-plugin@3.2.0(eslint@8.57.1(supports-color@8.1.1))(webpack@5.107.1(clean-css@5.3.3)(cssnano@5.1.15(postcss@8.5.15))(csso@4.2.0)(html-minifier-terser@6.1.0)(postcss@8.5.15)(uglify-js@3.19.3)): dependencies: '@types/eslint': 8.56.12 - eslint: 8.57.1 + eslint: 8.57.1(supports-color@8.1.1) jest-worker: 28.1.3 micromatch: 4.0.8 normalize-path: 3.0.0 schema-utils: 4.3.3 - webpack: 5.107.1(postcss@8.5.15) + webpack: 5.107.1(clean-css@5.3.3)(cssnano@5.1.15(postcss@8.5.15))(csso@4.2.0)(html-minifier-terser@6.1.0)(postcss@8.5.15)(uglify-js@3.19.3) - eslint@8.57.1: + eslint@8.57.1(supports-color@8.1.1): dependencies: - '@eslint-community/eslint-utils': 4.9.1(eslint@8.57.1) + '@eslint-community/eslint-utils': 4.9.1(eslint@8.57.1(supports-color@8.1.1)) '@eslint-community/regexpp': 4.12.2 - '@eslint/eslintrc': 2.1.4 + '@eslint/eslintrc': 2.1.4(supports-color@8.1.1) '@eslint/js': 8.57.1 - '@humanwhocodes/config-array': 0.13.0 + '@humanwhocodes/config-array': 0.13.0(supports-color@8.1.1) '@humanwhocodes/module-importer': 1.0.1 '@nodelib/fs.walk': 1.2.8 '@ungap/structured-clone': 1.3.1 ajv: 6.15.0 chalk: 4.1.2 cross-spawn: 7.0.6 - debug: 4.4.3 + debug: 4.4.3(supports-color@8.1.1) doctrine: 3.0.0 escape-string-regexp: 4.0.0 eslint-scope: 7.2.2 @@ -10009,21 +9936,21 @@ snapshots: jest-message-util: 29.7.0 jest-util: 29.7.0 - express@4.22.2: + express@4.22.2(supports-color@8.1.1): dependencies: accepts: 1.3.8 array-flatten: 1.1.1 - body-parser: 1.20.5 + body-parser: 1.20.5(supports-color@8.1.1) content-disposition: 0.5.4 content-type: 1.0.5 cookie: 0.7.2 cookie-signature: 1.0.7 - debug: 2.6.9 + debug: 2.6.9(supports-color@8.1.1) depd: 2.0.0 encodeurl: 2.0.0 escape-html: 1.0.3 etag: 1.8.1 - finalhandler: 1.3.2 + finalhandler: 1.3.2(supports-color@8.1.1) fresh: 0.5.2 http-errors: 2.0.1 merge-descriptors: 1.0.3 @@ -10035,8 +9962,8 @@ snapshots: qs: 6.15.2 range-parser: 1.2.1 safe-buffer: 5.2.1 - send: 0.19.2 - serve-static: 1.16.3 + send: 0.19.2(supports-color@8.1.1) + serve-static: 1.16.3(supports-color@8.1.1) setprototypeof: 1.2.0 statuses: 2.0.2 type-is: 1.6.18 @@ -10083,11 +10010,11 @@ snapshots: dependencies: flat-cache: 3.2.0 - file-loader@6.2.0(webpack@5.107.1(postcss@8.5.15)): + file-loader@6.2.0(webpack@5.107.1(clean-css@5.3.3)(cssnano@5.1.15(postcss@8.5.15))(csso@4.2.0)(html-minifier-terser@6.1.0)(postcss@8.5.15)(uglify-js@3.19.3)): dependencies: loader-utils: 2.0.4 schema-utils: 3.3.0 - webpack: 5.107.1(postcss@8.5.15) + webpack: 5.107.1(clean-css@5.3.3)(cssnano@5.1.15(postcss@8.5.15))(csso@4.2.0)(html-minifier-terser@6.1.0)(postcss@8.5.15)(uglify-js@3.19.3) filelist@1.0.6: dependencies: @@ -10099,9 +10026,9 @@ snapshots: dependencies: to-regex-range: 5.0.1 - finalhandler@1.3.2: + finalhandler@1.3.2(supports-color@8.1.1): dependencies: - debug: 2.6.9 + debug: 2.6.9(supports-color@8.1.1) encodeurl: 2.0.0 escape-html: 1.0.3 on-finished: 2.4.1 @@ -10139,15 +10066,15 @@ snapshots: flatted@3.4.2: {} - follow-redirects@1.16.0(debug@4.4.3): + follow-redirects@1.16.0(debug@4.4.3(supports-color@8.1.1)): optionalDependencies: - debug: 4.4.3 + debug: 4.4.3(supports-color@8.1.1) for-each@0.3.5: dependencies: is-callable: 1.2.7 - fork-ts-checker-webpack-plugin@6.5.3(eslint@8.57.1)(typescript@4.9.5)(webpack@5.107.1(postcss@8.5.15)): + fork-ts-checker-webpack-plugin@6.5.3(eslint@8.57.1(supports-color@8.1.1))(typescript@4.9.5)(webpack@5.107.1(clean-css@5.3.3)(cssnano@5.1.15(postcss@8.5.15))(csso@4.2.0)(html-minifier-terser@6.1.0)(postcss@8.5.15)(uglify-js@3.19.3)): dependencies: '@babel/code-frame': 7.29.7 '@types/json-schema': 7.0.15 @@ -10163,9 +10090,9 @@ snapshots: semver: 7.8.5 tapable: 1.1.3 typescript: 4.9.5 - webpack: 5.107.1(postcss@8.5.15) + webpack: 5.107.1(clean-css@5.3.3)(cssnano@5.1.15(postcss@8.5.15))(csso@4.2.0)(html-minifier-terser@6.1.0)(postcss@8.5.15)(uglify-js@3.19.3) optionalDependencies: - eslint: 8.57.1 + eslint: 8.57.1(supports-color@8.1.1) form-data@3.0.5: dependencies: @@ -10311,15 +10238,6 @@ snapshots: handle-thing@2.0.1: {} - handlebars@4.7.9: - dependencies: - minimist: 1.2.8 - neo-async: 2.6.2 - source-map: 0.6.1 - wordwrap: 1.0.0 - optionalDependencies: - uglify-js: 3.19.3 - harmony-reflect@1.6.2: {} has-bigints@1.1.0: {} @@ -10350,19 +10268,6 @@ snapshots: he@1.2.0: {} - history@4.10.1: - dependencies: - '@babel/runtime': 7.29.7 - loose-envify: 1.4.0 - resolve-pathname: 3.0.0 - tiny-invariant: 1.3.3 - tiny-warning: 1.0.3 - value-equal: 1.0.1 - - hoist-non-react-statics@3.3.2: - dependencies: - react-is: 16.13.1 - hoopy@0.1.4: {} hpack.js@2.1.6: @@ -10395,7 +10300,7 @@ snapshots: relateurl: 0.2.7 terser: 5.48.0 - html-webpack-plugin@5.6.7(webpack@5.107.1(postcss@8.5.15)): + html-webpack-plugin@5.6.7(webpack@5.107.1(clean-css@5.3.3)(cssnano@5.1.15(postcss@8.5.15))(csso@4.2.0)(html-minifier-terser@6.1.0)(postcss@8.5.15)(uglify-js@3.19.3)): dependencies: '@types/html-minifier-terser': 6.1.0 html-minifier-terser: 6.1.0 @@ -10403,7 +10308,7 @@ snapshots: pretty-error: 4.0.0 tapable: 2.3.3 optionalDependencies: - webpack: 5.107.1(postcss@8.5.15) + webpack: 5.107.1(clean-css@5.3.3)(cssnano@5.1.15(postcss@8.5.15))(csso@4.2.0)(html-minifier-terser@6.1.0)(postcss@8.5.15)(uglify-js@3.19.3) htmlparser2@10.1.0: dependencies: @@ -10426,6 +10331,13 @@ snapshots: domutils: 2.8.0 entities: 2.2.0 + htmlparser2@8.0.2: + dependencies: + domelementtype: 2.3.0 + domhandler: 5.0.3 + domutils: 3.2.2 + entities: 4.5.0 + http-deceiver@1.2.7: {} http-errors@1.8.1: @@ -10446,18 +10358,18 @@ snapshots: http-parser-js@0.5.10: {} - http-proxy-agent@4.0.1: + http-proxy-agent@4.0.1(supports-color@8.1.1): dependencies: '@tootallnate/once': 1.1.2 - agent-base: 6.0.2 - debug: 4.4.3 + agent-base: 6.0.2(supports-color@8.1.1) + debug: 4.4.3(supports-color@8.1.1) transitivePeerDependencies: - supports-color - http-proxy-middleware@2.0.9(@types/express@4.17.25): + http-proxy-middleware@2.0.9(@types/express@4.17.25)(debug@4.4.3(supports-color@8.1.1)): dependencies: '@types/http-proxy': 1.17.17 - http-proxy: 1.18.1(debug@4.4.3) + http-proxy: 1.18.1(debug@4.4.3(supports-color@8.1.1)) is-glob: 4.0.3 is-plain-obj: 3.0.0 micromatch: 4.0.8 @@ -10466,29 +10378,29 @@ snapshots: transitivePeerDependencies: - debug - http-proxy-middleware@3.0.7: + http-proxy-middleware@3.0.7(supports-color@8.1.1): dependencies: '@types/http-proxy': 1.17.17 - debug: 4.4.3 - http-proxy: 1.18.1(debug@4.4.3) + debug: 4.4.3(supports-color@8.1.1) + http-proxy: 1.18.1(debug@4.4.3(supports-color@8.1.1)) is-glob: 4.0.3 is-plain-object: 5.0.0 micromatch: 4.0.8 transitivePeerDependencies: - supports-color - http-proxy@1.18.1(debug@4.4.3): + http-proxy@1.18.1(debug@4.4.3(supports-color@8.1.1)): dependencies: eventemitter3: 4.0.7 - follow-redirects: 1.16.0(debug@4.4.3) + follow-redirects: 1.16.0(debug@4.4.3(supports-color@8.1.1)) requires-port: 1.0.0 transitivePeerDependencies: - debug - https-proxy-agent@5.0.1: + https-proxy-agent@5.0.1(supports-color@8.1.1): dependencies: - agent-base: 6.0.2 - debug: 4.4.3 + agent-base: 6.0.2(supports-color@8.1.1) + debug: 4.4.3(supports-color@8.1.1) transitivePeerDependencies: - supports-color @@ -10700,8 +10612,6 @@ snapshots: dependencies: is-docker: 2.2.1 - isarray@0.0.1: {} - isarray@1.0.0: {} isarray@2.0.5: {} @@ -10710,9 +10620,9 @@ snapshots: istanbul-lib-coverage@3.2.2: {} - istanbul-lib-instrument@5.2.1: + istanbul-lib-instrument@5.2.1(supports-color@8.1.1): dependencies: - '@babel/core': 7.29.7 + '@babel/core': 7.29.7(supports-color@8.1.1) '@babel/parser': 7.29.7 '@istanbuljs/schema': 0.1.6 istanbul-lib-coverage: 3.2.2 @@ -10726,9 +10636,9 @@ snapshots: make-dir: 4.0.0 supports-color: 7.2.0 - istanbul-lib-source-maps@4.0.1: + istanbul-lib-source-maps@4.0.1(supports-color@8.1.1): dependencies: - debug: 4.4.3 + debug: 4.4.3(supports-color@8.1.1) istanbul-lib-coverage: 3.2.2 source-map: 0.6.1 transitivePeerDependencies: @@ -10765,7 +10675,7 @@ snapshots: execa: 5.1.1 throat: 6.0.2 - jest-circus@27.5.1: + jest-circus@27.5.1(supports-color@8.1.1): dependencies: '@jest/environment': 27.5.1 '@jest/test-result': 27.5.1 @@ -10779,8 +10689,8 @@ snapshots: jest-each: 27.5.1 jest-matcher-utils: 27.5.1 jest-message-util: 27.5.1 - jest-runtime: 27.5.1 - jest-snapshot: 27.5.1 + jest-runtime: 27.5.1(supports-color@8.1.1) + jest-snapshot: 27.5.1(supports-color@8.1.1) jest-util: 27.5.1 pretty-format: 27.5.1 slash: 3.0.0 @@ -10789,16 +10699,16 @@ snapshots: transitivePeerDependencies: - supports-color - jest-cli@27.5.1: + jest-cli@27.5.1(supports-color@8.1.1): dependencies: - '@jest/core': 27.5.1 + '@jest/core': 27.5.1(supports-color@8.1.1) '@jest/test-result': 27.5.1 '@jest/types': 27.5.1 chalk: 4.1.2 exit: 0.1.2 graceful-fs: 4.2.11 import-local: 3.2.0 - jest-config: 27.5.1 + jest-config: 27.5.1(supports-color@8.1.1) jest-util: 27.5.1 jest-validate: 27.5.1 prompts: 2.4.2 @@ -10810,25 +10720,25 @@ snapshots: - ts-node - utf-8-validate - jest-config@27.5.1: + jest-config@27.5.1(supports-color@8.1.1): dependencies: - '@babel/core': 7.29.7 - '@jest/test-sequencer': 27.5.1 + '@babel/core': 7.29.7(supports-color@8.1.1) + '@jest/test-sequencer': 27.5.1(supports-color@8.1.1) '@jest/types': 27.5.1 - babel-jest: 27.5.1(@babel/core@7.29.7) + babel-jest: 27.5.1(@babel/core@7.29.7(supports-color@8.1.1))(supports-color@8.1.1) chalk: 4.1.2 ci-info: 3.9.0 deepmerge: 4.3.1 glob: 7.2.3 graceful-fs: 4.2.11 - jest-circus: 27.5.1 - jest-environment-jsdom: 27.5.1 + jest-circus: 27.5.1(supports-color@8.1.1) + jest-environment-jsdom: 27.5.1(supports-color@8.1.1) jest-environment-node: 27.5.1 jest-get-type: 27.5.1 - jest-jasmine2: 27.5.1 + jest-jasmine2: 27.5.1(supports-color@8.1.1) jest-regex-util: 27.5.1 jest-resolve: 27.5.1 - jest-runner: 27.5.1 + jest-runner: 27.5.1(supports-color@8.1.1) jest-util: 27.5.1 jest-validate: 27.5.1 micromatch: 4.0.8 @@ -10868,7 +10778,7 @@ snapshots: jest-util: 27.5.1 pretty-format: 27.5.1 - jest-environment-jsdom@27.5.1: + jest-environment-jsdom@27.5.1(supports-color@8.1.1): dependencies: '@jest/environment': 27.5.1 '@jest/fake-timers': 27.5.1 @@ -10876,7 +10786,7 @@ snapshots: '@types/node': 22.20.1 jest-mock: 27.5.1 jest-util: 27.5.1 - jsdom: 16.7.0 + jsdom: 16.7.0(supports-color@8.1.1) transitivePeerDependencies: - bufferutil - canvas @@ -10920,7 +10830,7 @@ snapshots: optionalDependencies: fsevents: 2.3.3 - jest-jasmine2@27.5.1: + jest-jasmine2@27.5.1(supports-color@8.1.1): dependencies: '@jest/environment': 27.5.1 '@jest/source-map': 27.5.1 @@ -10934,8 +10844,8 @@ snapshots: jest-each: 27.5.1 jest-matcher-utils: 27.5.1 jest-message-util: 27.5.1 - jest-runtime: 27.5.1 - jest-snapshot: 27.5.1 + jest-runtime: 27.5.1(supports-color@8.1.1) + jest-snapshot: 27.5.1(supports-color@8.1.1) jest-util: 27.5.1 pretty-format: 27.5.1 throat: 6.0.2 @@ -11010,11 +10920,11 @@ snapshots: jest-regex-util@28.0.2: {} - jest-resolve-dependencies@27.5.1: + jest-resolve-dependencies@27.5.1(supports-color@8.1.1): dependencies: '@jest/types': 27.5.1 jest-regex-util: 27.5.1 - jest-snapshot: 27.5.1 + jest-snapshot: 27.5.1(supports-color@8.1.1) transitivePeerDependencies: - supports-color @@ -11031,25 +10941,25 @@ snapshots: resolve.exports: 1.1.1 slash: 3.0.0 - jest-runner@27.5.1: + jest-runner@27.5.1(supports-color@8.1.1): dependencies: '@jest/console': 27.5.1 '@jest/environment': 27.5.1 '@jest/test-result': 27.5.1 - '@jest/transform': 27.5.1 + '@jest/transform': 27.5.1(supports-color@8.1.1) '@jest/types': 27.5.1 '@types/node': 22.20.1 chalk: 4.1.2 emittery: 0.8.1 graceful-fs: 4.2.11 jest-docblock: 27.5.1 - jest-environment-jsdom: 27.5.1 + jest-environment-jsdom: 27.5.1(supports-color@8.1.1) jest-environment-node: 27.5.1 jest-haste-map: 27.5.1 jest-leak-detector: 27.5.1 jest-message-util: 27.5.1 jest-resolve: 27.5.1 - jest-runtime: 27.5.1 + jest-runtime: 27.5.1(supports-color@8.1.1) jest-util: 27.5.1 jest-worker: 27.5.1 source-map-support: 0.5.21 @@ -11060,14 +10970,14 @@ snapshots: - supports-color - utf-8-validate - jest-runtime@27.5.1: + jest-runtime@27.5.1(supports-color@8.1.1): dependencies: '@jest/environment': 27.5.1 '@jest/fake-timers': 27.5.1 '@jest/globals': 27.5.1 '@jest/source-map': 27.5.1 '@jest/test-result': 27.5.1 - '@jest/transform': 27.5.1 + '@jest/transform': 27.5.1(supports-color@8.1.1) '@jest/types': 27.5.1 chalk: 4.1.2 cjs-module-lexer: 1.4.3 @@ -11080,7 +10990,7 @@ snapshots: jest-mock: 27.5.1 jest-regex-util: 27.5.1 jest-resolve: 27.5.1 - jest-snapshot: 27.5.1 + jest-snapshot: 27.5.1(supports-color@8.1.1) jest-util: 27.5.1 slash: 3.0.0 strip-bom: 4.0.0 @@ -11092,18 +11002,18 @@ snapshots: '@types/node': 22.20.1 graceful-fs: 4.2.11 - jest-snapshot@27.5.1: + jest-snapshot@27.5.1(supports-color@8.1.1): dependencies: - '@babel/core': 7.29.7 + '@babel/core': 7.29.7(supports-color@8.1.1) '@babel/generator': 7.29.7 - '@babel/plugin-syntax-typescript': 7.29.7(@babel/core@7.29.7) - '@babel/traverse': 7.29.7 + '@babel/plugin-syntax-typescript': 7.29.7(@babel/core@7.29.7(supports-color@8.1.1)) + '@babel/traverse': 7.29.7(supports-color@8.1.1) '@babel/types': 7.29.7 - '@jest/transform': 27.5.1 + '@jest/transform': 27.5.1(supports-color@8.1.1) '@jest/types': 27.5.1 '@types/babel__traverse': 7.28.0 '@types/prettier': 2.7.3 - babel-preset-current-node-syntax: 1.2.0(@babel/core@7.29.7) + babel-preset-current-node-syntax: 1.2.0(@babel/core@7.29.7(supports-color@8.1.1)) chalk: 4.1.2 expect: 27.5.1 graceful-fs: 4.2.11 @@ -11155,11 +11065,11 @@ snapshots: leven: 3.1.0 pretty-format: 27.5.1 - jest-watch-typeahead@1.1.0(jest@27.5.1): + jest-watch-typeahead@1.1.0(jest@27.5.1(supports-color@8.1.1)): dependencies: ansi-escapes: 4.3.2 chalk: 4.1.2 - jest: 27.5.1 + jest: 27.5.1(supports-color@8.1.1) jest-regex-util: 28.0.2 jest-watcher: 28.1.3 slash: 4.0.0 @@ -11205,11 +11115,11 @@ snapshots: merge-stream: 2.0.0 supports-color: 8.1.1 - jest@27.5.1: + jest@27.5.1(supports-color@8.1.1): dependencies: - '@jest/core': 27.5.1 + '@jest/core': 27.5.1(supports-color@8.1.1) import-local: 3.2.0 - jest-cli: 27.5.1 + jest-cli: 27.5.1(supports-color@8.1.1) transitivePeerDependencies: - bufferutil - canvas @@ -11234,7 +11144,7 @@ snapshots: dependencies: argparse: 2.0.1 - jsdom@16.7.0: + jsdom@16.7.0(supports-color@8.1.1): dependencies: abab: 2.0.6 acorn: 8.17.0 @@ -11247,8 +11157,8 @@ snapshots: escodegen: 2.1.0 form-data: 3.0.5 html-encoding-sniffer: 2.0.1 - http-proxy-agent: 4.0.1 - https-proxy-agent: 5.0.1 + http-proxy-agent: 4.0.1(supports-color@8.1.1) + https-proxy-agent: 5.0.1(supports-color@8.1.1) is-potential-custom-element-name: 1.0.1 nwsapi: 2.2.24 parse5: 6.0.1 @@ -11400,6 +11310,8 @@ snapshots: dependencies: yallist: 3.1.1 + lz-string@1.5.0: {} + magic-string@0.25.9: dependencies: sourcemap-codec: 1.4.8 @@ -11412,8 +11324,6 @@ snapshots: dependencies: semver: 7.8.5 - make-error@1.3.6: {} - makeerror@1.0.12: dependencies: tmpl: 1.0.5 @@ -11455,11 +11365,11 @@ snapshots: mimic-fn@2.1.0: {} - mini-css-extract-plugin@2.10.2(webpack@5.107.1(postcss@8.5.15)): + mini-css-extract-plugin@2.10.2(webpack@5.107.1(clean-css@5.3.3)(cssnano@5.1.15(postcss@8.5.15))(csso@4.2.0)(html-minifier-terser@6.1.0)(postcss@8.5.15)(uglify-js@3.19.3)): dependencies: schema-utils: 4.3.3 tapable: 2.3.3 - webpack: 5.107.1(postcss@8.5.15) + webpack: 5.107.1(clean-css@5.3.3)(cssnano@5.1.15(postcss@8.5.15))(csso@4.2.0)(html-minifier-terser@6.1.0)(postcss@8.5.15)(uglify-js@3.19.3) minimalistic-assert@1.0.1: {} @@ -11721,10 +11631,6 @@ snapshots: domhandler: 5.0.3 parse5: 7.3.0 - parse5-parser-stream@7.1.2: - dependencies: - parse5: 7.3.0 - parse5@6.0.1: {} parse5@7.3.0: @@ -11750,10 +11656,6 @@ snapshots: path-to-regexp@0.1.13: {} - path-to-regexp@1.9.0: - dependencies: - isarray: 0.0.1 - path-to-regexp@8.4.2: {} path-type@4.0.0: {} @@ -11937,13 +11839,13 @@ snapshots: jiti: 1.21.7 postcss: 8.5.15 - postcss-loader@6.2.1(postcss@8.5.15)(webpack@5.107.1(postcss@8.5.15)): + postcss-loader@6.2.1(postcss@8.5.15)(webpack@5.107.1(clean-css@5.3.3)(cssnano@5.1.15(postcss@8.5.15))(csso@4.2.0)(html-minifier-terser@6.1.0)(postcss@8.5.15)(uglify-js@3.19.3)): dependencies: cosmiconfig: 7.1.0 klona: 2.0.6 postcss: 8.5.15 semver: 7.8.5 - webpack: 5.107.1(postcss@8.5.15) + webpack: 5.107.1(clean-css@5.3.3)(cssnano@5.1.15(postcss@8.5.15))(csso@4.2.0)(html-minifier-terser@6.1.0)(postcss@8.5.15)(uglify-js@3.19.3) postcss-logical@5.0.4(postcss@8.5.15): dependencies: @@ -12318,29 +12220,29 @@ snapshots: regenerator-runtime: 0.13.11 whatwg-fetch: 3.6.20 - react-app-rewired@2.2.1(react-scripts@5.0.1(@babel/plugin-syntax-flow@7.29.7(@babel/core@7.29.7))(@babel/plugin-transform-react-jsx@7.29.7(@babel/core@7.29.7))(@types/babel__core@7.20.5)(eslint@8.57.1)(react@17.0.2)(sass@1.102.0)(type-fest@4.41.0)(typescript@4.9.5)): + react-app-rewired@2.2.1(react-scripts@5.0.1(@babel/plugin-syntax-flow@7.29.7(@babel/core@7.29.7(supports-color@8.1.1)))(@babel/plugin-transform-react-jsx@7.29.7(@babel/core@7.29.7(supports-color@8.1.1))(supports-color@8.1.1))(@types/babel__core@7.20.5)(clean-css@5.3.3)(cssnano@5.1.15(postcss@8.5.15))(csso@4.2.0)(debug@4.4.3(supports-color@8.1.1))(eslint@8.57.1(supports-color@8.1.1))(html-minifier-terser@6.1.0)(react@18.3.1)(sass@1.102.0)(supports-color@8.1.1)(type-fest@4.41.0)(typescript@4.9.5)(uglify-js@3.19.3)): dependencies: - react-scripts: 5.0.1(@babel/plugin-syntax-flow@7.29.7(@babel/core@7.29.7))(@babel/plugin-transform-react-jsx@7.29.7(@babel/core@7.29.7))(@types/babel__core@7.20.5)(eslint@8.57.1)(react@17.0.2)(sass@1.102.0)(type-fest@4.41.0)(typescript@4.9.5) + react-scripts: 5.0.1(@babel/plugin-syntax-flow@7.29.7(@babel/core@7.29.7(supports-color@8.1.1)))(@babel/plugin-transform-react-jsx@7.29.7(@babel/core@7.29.7(supports-color@8.1.1))(supports-color@8.1.1))(@types/babel__core@7.20.5)(clean-css@5.3.3)(cssnano@5.1.15(postcss@8.5.15))(csso@4.2.0)(debug@4.4.3(supports-color@8.1.1))(eslint@8.57.1(supports-color@8.1.1))(html-minifier-terser@6.1.0)(react@18.3.1)(sass@1.102.0)(supports-color@8.1.1)(type-fest@4.41.0)(typescript@4.9.5)(uglify-js@3.19.3) semver: 5.7.2 - react-copy-to-clipboard@5.1.1(react@17.0.2): + react-copy-to-clipboard@5.1.1(react@18.3.1): dependencies: copy-to-clipboard: 3.3.3 prop-types: 15.8.1 - react: 17.0.2 + react: 18.3.1 - react-dev-utils@12.0.1(eslint@8.57.1)(typescript@4.9.5)(webpack@5.107.1(postcss@8.5.15)): + react-dev-utils@12.0.1(eslint@8.57.1(supports-color@8.1.1))(supports-color@8.1.1)(typescript@4.9.5)(webpack@5.107.1(clean-css@5.3.3)(cssnano@5.1.15(postcss@8.5.15))(csso@4.2.0)(html-minifier-terser@6.1.0)(postcss@8.5.15)(uglify-js@3.19.3)): dependencies: '@babel/code-frame': 7.29.7 address: 1.2.2 browserslist: 4.28.2 chalk: 4.1.2 cross-spawn: 7.0.6 - detect-port-alt: 1.1.6 + detect-port-alt: 1.1.6(supports-color@8.1.1) escape-string-regexp: 4.0.0 filesize: 8.0.7 find-up: 5.0.0 - fork-ts-checker-webpack-plugin: 6.5.3(eslint@8.57.1)(typescript@4.9.5)(webpack@5.107.1(postcss@8.5.15)) + fork-ts-checker-webpack-plugin: 6.5.3(eslint@8.57.1(supports-color@8.1.1))(typescript@4.9.5)(webpack@5.107.1(clean-css@5.3.3)(cssnano@5.1.15(postcss@8.5.15))(csso@4.2.0)(html-minifier-terser@6.1.0)(postcss@8.5.15)(uglify-js@3.19.3)) global-modules: 2.0.0 globby: 11.1.0 gzip-size: 6.0.0 @@ -12355,7 +12257,7 @@ snapshots: shell-quote: 1.8.4 strip-ansi: 6.0.1 text-table: 0.2.0 - webpack: 5.107.1(postcss@8.5.15) + webpack: 5.107.1(clean-css@5.3.3)(cssnano@5.1.15(postcss@8.5.15))(csso@4.2.0)(html-minifier-terser@6.1.0)(postcss@8.5.15)(uglify-js@3.19.3) optionalDependencies: typescript: 4.9.5 transitivePeerDependencies: @@ -12363,23 +12265,17 @@ snapshots: - supports-color - vue-template-compiler - react-dom@17.0.2(react@17.0.2): + react-dom@18.3.1(react@18.3.1): dependencies: loose-envify: 1.4.0 - object-assign: 4.1.1 - react: 17.0.2 - scheduler: 0.20.2 - - react-error-boundary@3.1.4(react@17.0.2): - dependencies: - '@babel/runtime': 7.29.7 - react: 17.0.2 + react: 18.3.1 + scheduler: 0.23.2 react-error-overlay@6.1.0: {} - react-infinite-scroll-component@6.1.1(react@17.0.2): + react-infinite-scroll-component@6.1.1(react@18.3.1): dependencies: - react: 17.0.2 + react: 18.3.1 throttle-debounce: 2.3.0 react-is@16.13.1: {} @@ -12390,99 +12286,89 @@ snapshots: react-lifecycles-compat@3.0.4: {} - react-popper@1.3.11(react@17.0.2): + react-popper@1.3.11(react@18.3.1): dependencies: '@babel/runtime': 7.29.7 - '@hypnosphi/create-react-context': 0.3.1(prop-types@15.8.1)(react@17.0.2) + '@hypnosphi/create-react-context': 0.3.1(prop-types@15.8.1)(react@18.3.1) deep-equal: 1.1.2 popper.js: 1.16.1 prop-types: 15.8.1 - react: 17.0.2 + react: 18.3.1 typed-styles: 0.0.7 warning: 4.0.3 react-refresh@0.11.0: {} - react-resize-detector@7.1.2(react-dom@17.0.2(react@17.0.2))(react@17.0.2): + react-resize-detector@7.1.2(react-dom@18.3.1(react@18.3.1))(react@18.3.1): dependencies: lodash: 4.18.1 - react: 17.0.2 - react-dom: 17.0.2(react@17.0.2) + react: 18.3.1 + react-dom: 18.3.1(react@18.3.1) - react-router-dom@5.3.4(react@17.0.2): + react-router-dom@7.18.2(react-dom@18.3.1(react@18.3.1))(react@18.3.1): dependencies: - '@babel/runtime': 7.29.7 - history: 4.10.1 - loose-envify: 1.4.0 - prop-types: 15.8.1 - react: 17.0.2 - react-router: 5.3.4(react@17.0.2) - tiny-invariant: 1.3.3 - tiny-warning: 1.0.3 + react: 18.3.1 + react-dom: 18.3.1(react@18.3.1) + react-router: 7.18.2(react-dom@18.3.1(react@18.3.1))(react@18.3.1) - react-router@5.3.4(react@17.0.2): + react-router@7.18.2(react-dom@18.3.1(react@18.3.1))(react@18.3.1): dependencies: - '@babel/runtime': 7.29.7 - history: 4.10.1 - hoist-non-react-statics: 3.3.2 - loose-envify: 1.4.0 - path-to-regexp: 1.9.0 - prop-types: 15.8.1 - react: 17.0.2 - react-is: 16.13.1 - tiny-invariant: 1.3.3 - tiny-warning: 1.0.3 - - react-scripts@5.0.1(@babel/plugin-syntax-flow@7.29.7(@babel/core@7.29.7))(@babel/plugin-transform-react-jsx@7.29.7(@babel/core@7.29.7))(@types/babel__core@7.20.5)(eslint@8.57.1)(react@17.0.2)(sass@1.102.0)(type-fest@4.41.0)(typescript@4.9.5): - dependencies: - '@babel/core': 7.29.7 - '@pmmmwh/react-refresh-webpack-plugin': 0.5.17(react-refresh@0.11.0)(type-fest@4.41.0)(webpack-dev-server@4.15.2(webpack@5.107.1(postcss@8.5.15)))(webpack@5.107.1(postcss@8.5.15)) - '@svgr/webpack': 5.5.0 - babel-jest: 27.5.1(@babel/core@7.29.7) - babel-loader: 8.4.1(@babel/core@7.29.7)(webpack@5.107.1(postcss@8.5.15)) - babel-plugin-named-asset-import: 0.3.8(@babel/core@7.29.7) - babel-preset-react-app: 10.1.0 + cookie: 1.1.1 + react: 18.3.1 + set-cookie-parser: 2.7.2 + optionalDependencies: + react-dom: 18.3.1(react@18.3.1) + + react-scripts@5.0.1(@babel/plugin-syntax-flow@7.29.7(@babel/core@7.29.7(supports-color@8.1.1)))(@babel/plugin-transform-react-jsx@7.29.7(@babel/core@7.29.7(supports-color@8.1.1))(supports-color@8.1.1))(@types/babel__core@7.20.5)(clean-css@5.3.3)(cssnano@5.1.15(postcss@8.5.15))(csso@4.2.0)(debug@4.4.3(supports-color@8.1.1))(eslint@8.57.1(supports-color@8.1.1))(html-minifier-terser@6.1.0)(react@18.3.1)(sass@1.102.0)(supports-color@8.1.1)(type-fest@4.41.0)(typescript@4.9.5)(uglify-js@3.19.3): + dependencies: + '@babel/core': 7.29.7(supports-color@8.1.1) + '@pmmmwh/react-refresh-webpack-plugin': 0.5.17(react-refresh@0.11.0)(type-fest@4.41.0)(webpack-dev-server@4.15.2(debug@4.4.3(supports-color@8.1.1))(supports-color@8.1.1)(webpack@5.107.1(clean-css@5.3.3)(cssnano@5.1.15(postcss@8.5.15))(csso@4.2.0)(html-minifier-terser@6.1.0)(postcss@8.5.15)(uglify-js@3.19.3)))(webpack@5.107.1(clean-css@5.3.3)(cssnano@5.1.15(postcss@8.5.15))(csso@4.2.0)(html-minifier-terser@6.1.0)(postcss@8.5.15)(uglify-js@3.19.3)) + '@svgr/webpack': 5.5.0(supports-color@8.1.1) + babel-jest: 27.5.1(@babel/core@7.29.7(supports-color@8.1.1))(supports-color@8.1.1) + babel-loader: 8.4.1(@babel/core@7.29.7(supports-color@8.1.1))(webpack@5.107.1(clean-css@5.3.3)(cssnano@5.1.15(postcss@8.5.15))(csso@4.2.0)(html-minifier-terser@6.1.0)(postcss@8.5.15)(uglify-js@3.19.3)) + babel-plugin-named-asset-import: 0.3.8(@babel/core@7.29.7(supports-color@8.1.1)) + babel-preset-react-app: 10.1.0(supports-color@8.1.1) bfj: 7.1.0 browserslist: 4.28.2 camelcase: 6.3.0 case-sensitive-paths-webpack-plugin: 2.4.0 - css-loader: 6.11.0(webpack@5.107.1(postcss@8.5.15)) - css-minimizer-webpack-plugin: 3.4.1(webpack@5.107.1(postcss@8.5.15)) + css-loader: 6.11.0(webpack@5.107.1(clean-css@5.3.3)(cssnano@5.1.15(postcss@8.5.15))(csso@4.2.0)(html-minifier-terser@6.1.0)(postcss@8.5.15)(uglify-js@3.19.3)) + css-minimizer-webpack-plugin: 3.4.1(clean-css@5.3.3)(csso@4.2.0)(webpack@5.107.1(clean-css@5.3.3)(cssnano@5.1.15(postcss@8.5.15))(csso@4.2.0)(html-minifier-terser@6.1.0)(postcss@8.5.15)(uglify-js@3.19.3)) dotenv: 10.0.0 dotenv-expand: 5.1.0 - eslint: 8.57.1 - eslint-config-react-app: 7.0.1(@babel/plugin-syntax-flow@7.29.7(@babel/core@7.29.7))(@babel/plugin-transform-react-jsx@7.29.7(@babel/core@7.29.7))(eslint@8.57.1)(jest@27.5.1)(typescript@4.9.5) - eslint-webpack-plugin: 3.2.0(eslint@8.57.1)(webpack@5.107.1(postcss@8.5.15)) - file-loader: 6.2.0(webpack@5.107.1(postcss@8.5.15)) + eslint: 8.57.1(supports-color@8.1.1) + eslint-config-react-app: 7.0.1(@babel/plugin-syntax-flow@7.29.7(@babel/core@7.29.7(supports-color@8.1.1)))(@babel/plugin-transform-react-jsx@7.29.7(@babel/core@7.29.7(supports-color@8.1.1))(supports-color@8.1.1))(eslint@8.57.1(supports-color@8.1.1))(jest@27.5.1(supports-color@8.1.1))(supports-color@8.1.1)(typescript@4.9.5) + eslint-webpack-plugin: 3.2.0(eslint@8.57.1(supports-color@8.1.1))(webpack@5.107.1(clean-css@5.3.3)(cssnano@5.1.15(postcss@8.5.15))(csso@4.2.0)(html-minifier-terser@6.1.0)(postcss@8.5.15)(uglify-js@3.19.3)) + file-loader: 6.2.0(webpack@5.107.1(clean-css@5.3.3)(cssnano@5.1.15(postcss@8.5.15))(csso@4.2.0)(html-minifier-terser@6.1.0)(postcss@8.5.15)(uglify-js@3.19.3)) fs-extra: 10.1.0 - html-webpack-plugin: 5.6.7(webpack@5.107.1(postcss@8.5.15)) + html-webpack-plugin: 5.6.7(webpack@5.107.1(clean-css@5.3.3)(cssnano@5.1.15(postcss@8.5.15))(csso@4.2.0)(html-minifier-terser@6.1.0)(postcss@8.5.15)(uglify-js@3.19.3)) identity-obj-proxy: 3.0.0 - jest: 27.5.1 + jest: 27.5.1(supports-color@8.1.1) jest-resolve: 27.5.1 - jest-watch-typeahead: 1.1.0(jest@27.5.1) - mini-css-extract-plugin: 2.10.2(webpack@5.107.1(postcss@8.5.15)) + jest-watch-typeahead: 1.1.0(jest@27.5.1(supports-color@8.1.1)) + mini-css-extract-plugin: 2.10.2(webpack@5.107.1(clean-css@5.3.3)(cssnano@5.1.15(postcss@8.5.15))(csso@4.2.0)(html-minifier-terser@6.1.0)(postcss@8.5.15)(uglify-js@3.19.3)) postcss: 8.5.15 postcss-flexbugs-fixes: 5.0.2(postcss@8.5.15) - postcss-loader: 6.2.1(postcss@8.5.15)(webpack@5.107.1(postcss@8.5.15)) + postcss-loader: 6.2.1(postcss@8.5.15)(webpack@5.107.1(clean-css@5.3.3)(cssnano@5.1.15(postcss@8.5.15))(csso@4.2.0)(html-minifier-terser@6.1.0)(postcss@8.5.15)(uglify-js@3.19.3)) postcss-normalize: 10.0.1(browserslist@4.28.2)(postcss@8.5.15) postcss-preset-env: 7.8.3(postcss@8.5.15) prompts: 2.4.2 - react: 17.0.2 + react: 18.3.1 react-app-polyfill: 3.0.0 - react-dev-utils: 12.0.1(eslint@8.57.1)(typescript@4.9.5)(webpack@5.107.1(postcss@8.5.15)) + react-dev-utils: 12.0.1(eslint@8.57.1(supports-color@8.1.1))(supports-color@8.1.1)(typescript@4.9.5)(webpack@5.107.1(clean-css@5.3.3)(cssnano@5.1.15(postcss@8.5.15))(csso@4.2.0)(html-minifier-terser@6.1.0)(postcss@8.5.15)(uglify-js@3.19.3)) react-refresh: 0.11.0 resolve: 1.22.12 resolve-url-loader: 4.0.0 - sass-loader: 12.6.0(sass@1.102.0)(webpack@5.107.1(postcss@8.5.15)) + sass-loader: 12.6.0(sass@1.102.0)(webpack@5.107.1(clean-css@5.3.3)(cssnano@5.1.15(postcss@8.5.15))(csso@4.2.0)(html-minifier-terser@6.1.0)(postcss@8.5.15)(uglify-js@3.19.3)) semver: 7.8.5 - source-map-loader: 3.0.2(webpack@5.107.1(postcss@8.5.15)) - style-loader: 3.3.4(webpack@5.107.1(postcss@8.5.15)) + source-map-loader: 3.0.2(webpack@5.107.1(clean-css@5.3.3)(cssnano@5.1.15(postcss@8.5.15))(csso@4.2.0)(html-minifier-terser@6.1.0)(postcss@8.5.15)(uglify-js@3.19.3)) + style-loader: 3.3.4(webpack@5.107.1(clean-css@5.3.3)(cssnano@5.1.15(postcss@8.5.15))(csso@4.2.0)(html-minifier-terser@6.1.0)(postcss@8.5.15)(uglify-js@3.19.3)) tailwindcss: 3.4.19 - terser-webpack-plugin: 5.6.0(postcss@8.5.15)(webpack@5.107.1(postcss@8.5.15)) - webpack: 5.107.1(postcss@8.5.15) - webpack-dev-server: 4.15.2(webpack@5.107.1(postcss@8.5.15)) - webpack-manifest-plugin: 4.1.1(webpack@5.107.1(postcss@8.5.15)) - workbox-webpack-plugin: 6.6.0(@types/babel__core@7.20.5)(webpack@5.107.1(postcss@8.5.15)) + terser-webpack-plugin: 5.6.0(clean-css@5.3.3)(cssnano@5.1.15(postcss@8.5.15))(csso@4.2.0)(html-minifier-terser@6.1.0)(postcss@8.5.15)(uglify-js@3.19.3)(webpack@5.107.1(clean-css@5.3.3)(cssnano@5.1.15(postcss@8.5.15))(csso@4.2.0)(html-minifier-terser@6.1.0)(postcss@8.5.15)(uglify-js@3.19.3)) + webpack: 5.107.1(clean-css@5.3.3)(cssnano@5.1.15(postcss@8.5.15))(csso@4.2.0)(html-minifier-terser@6.1.0)(postcss@8.5.15)(uglify-js@3.19.3) + webpack-dev-server: 4.15.2(debug@4.4.3(supports-color@8.1.1))(supports-color@8.1.1)(webpack@5.107.1(clean-css@5.3.3)(cssnano@5.1.15(postcss@8.5.15))(csso@4.2.0)(html-minifier-terser@6.1.0)(postcss@8.5.15)(uglify-js@3.19.3)) + webpack-manifest-plugin: 4.1.1(webpack@5.107.1(clean-css@5.3.3)(cssnano@5.1.15(postcss@8.5.15))(csso@4.2.0)(html-minifier-terser@6.1.0)(postcss@8.5.15)(uglify-js@3.19.3)) + workbox-webpack-plugin: 6.6.0(@types/babel__core@7.20.5)(supports-color@8.1.1)(webpack@5.107.1(clean-css@5.3.3)(cssnano@5.1.15(postcss@8.5.15))(csso@4.2.0)(html-minifier-terser@6.1.0)(postcss@8.5.15)(uglify-js@3.19.3)) optionalDependencies: fsevents: 2.3.3 typescript: 4.9.5 @@ -12528,43 +12414,34 @@ snapshots: - webpack-plugin-serve - yaml - react-shallow-renderer@16.15.0(react@17.0.2): + react-shallow-renderer@16.15.0(react@18.3.1): dependencies: object-assign: 4.1.1 - react: 17.0.2 + react: 18.3.1 react-is: 18.3.1 - react-test-renderer@17.0.2(react@17.0.2): - dependencies: - object-assign: 4.1.1 - react: 17.0.2 - react-is: 17.0.2 - react-shallow-renderer: 16.15.0(react@17.0.2) - scheduler: 0.20.2 - - react-transition-group@3.0.0(react-dom@17.0.2(react@17.0.2))(react@17.0.2): + react-transition-group@3.0.0(react-dom@18.3.1(react@18.3.1))(react@18.3.1): dependencies: dom-helpers: 3.4.0 loose-envify: 1.4.0 prop-types: 15.8.1 - react: 17.0.2 - react-dom: 17.0.2(react@17.0.2) + react: 18.3.1 + react-dom: 18.3.1(react@18.3.1) react-lifecycles-compat: 3.0.4 - react@17.0.2: + react@18.3.1: dependencies: loose-envify: 1.4.0 - object-assign: 4.1.1 - reactstrap@8.10.1(react-dom@17.0.2(react@17.0.2))(react@17.0.2): + reactstrap@8.10.1(react-dom@18.3.1(react@18.3.1))(react@18.3.1): dependencies: '@babel/runtime': 7.29.7 classnames: 2.5.1 prop-types: 15.8.1 - react: 17.0.2 - react-dom: 17.0.2(react@17.0.2) - react-popper: 1.3.11(react@17.0.2) - react-transition-group: 3.0.0(react-dom@17.0.2(react@17.0.2))(react@17.0.2) + react: 18.3.1 + react-dom: 18.3.1(react@18.3.1) + react-popper: 1.3.11(react@18.3.1) + react-transition-group: 3.0.0(react-dom@18.3.1(react@18.3.1))(react@18.3.1) read-cache@1.0.0: dependencies: @@ -12665,8 +12542,6 @@ snapshots: resolve-from@5.0.0: {} - resolve-pathname@3.0.0: {} - resolve-url-loader@4.0.0: dependencies: adjust-sourcemap-loader: 4.0.0 @@ -12761,11 +12636,11 @@ snapshots: sanitize.css@13.0.0: {} - sass-loader@12.6.0(sass@1.102.0)(webpack@5.107.1(postcss@8.5.15)): + sass-loader@12.6.0(sass@1.102.0)(webpack@5.107.1(clean-css@5.3.3)(cssnano@5.1.15(postcss@8.5.15))(csso@4.2.0)(html-minifier-terser@6.1.0)(postcss@8.5.15)(uglify-js@3.19.3)): dependencies: klona: 2.0.6 neo-async: 2.6.2 - webpack: 5.107.1(postcss@8.5.15) + webpack: 5.107.1(clean-css@5.3.3)(cssnano@5.1.15(postcss@8.5.15))(csso@4.2.0)(html-minifier-terser@6.1.0)(postcss@8.5.15)(uglify-js@3.19.3) optionalDependencies: sass: 1.102.0 @@ -12785,10 +12660,9 @@ snapshots: dependencies: xmlchars: 2.2.0 - scheduler@0.20.2: + scheduler@0.23.2: dependencies: loose-envify: 1.4.0 - object-assign: 4.1.1 schema-utils@2.7.0: dependencies: @@ -12828,9 +12702,9 @@ snapshots: semver@7.8.5: {} - send@0.19.2: + send@0.19.2(supports-color@8.1.1): dependencies: - debug: 2.6.9 + debug: 2.6.9(supports-color@8.1.1) depd: 2.0.0 destroy: 1.2.0 encodeurl: 2.0.0 @@ -12854,11 +12728,11 @@ snapshots: dependencies: randombytes: 2.1.0 - serve-index@1.9.2: + serve-index@1.9.2(supports-color@8.1.1): dependencies: accepts: 1.3.8 batch: 0.6.1 - debug: 2.6.9 + debug: 2.6.9(supports-color@8.1.1) escape-html: 1.0.3 http-errors: 1.8.1 mime-types: 2.1.35 @@ -12866,15 +12740,17 @@ snapshots: transitivePeerDependencies: - supports-color - serve-static@1.16.3: + serve-static@1.16.3(supports-color@8.1.1): dependencies: encodeurl: 2.0.0 escape-html: 1.0.3 parseurl: 1.3.3 - send: 0.19.2 + send: 0.19.2(supports-color@8.1.1) transitivePeerDependencies: - supports-color + set-cookie-parser@2.7.2: {} + set-function-length@1.2.2: dependencies: define-data-property: 1.1.4 @@ -12962,12 +12838,12 @@ snapshots: source-map-js@1.2.1: {} - source-map-loader@3.0.2(webpack@5.107.1(postcss@8.5.15)): + source-map-loader@3.0.2(webpack@5.107.1(clean-css@5.3.3)(cssnano@5.1.15(postcss@8.5.15))(csso@4.2.0)(html-minifier-terser@6.1.0)(postcss@8.5.15)(uglify-js@3.19.3)): dependencies: abab: 2.0.6 iconv-lite: 0.6.3 source-map-js: 1.2.1 - webpack: 5.107.1(postcss@8.5.15) + webpack: 5.107.1(clean-css@5.3.3)(cssnano@5.1.15(postcss@8.5.15))(csso@4.2.0)(html-minifier-terser@6.1.0)(postcss@8.5.15)(uglify-js@3.19.3) source-map-support@0.5.21: dependencies: @@ -12984,9 +12860,9 @@ snapshots: sourcemap-codec@1.4.8: {} - spdy-transport@3.0.0: + spdy-transport@3.0.0(supports-color@8.1.1): dependencies: - debug: 4.4.3 + debug: 4.4.3(supports-color@8.1.1) detect-node: 2.1.0 hpack.js: 2.1.6 obuf: 1.1.2 @@ -12995,13 +12871,13 @@ snapshots: transitivePeerDependencies: - supports-color - spdy@4.0.2: + spdy@4.0.2(supports-color@8.1.1): dependencies: - debug: 4.4.3 + debug: 4.4.3(supports-color@8.1.1) handle-thing: 2.0.1 http-deceiver: 1.2.7 select-hose: 2.0.0 - spdy-transport: 3.0.0 + spdy-transport: 3.0.0(supports-color@8.1.1) transitivePeerDependencies: - supports-color @@ -13128,9 +13004,9 @@ snapshots: strip-json-comments@3.1.1: {} - style-loader@3.3.4(webpack@5.107.1(postcss@8.5.15)): + style-loader@3.3.4(webpack@5.107.1(clean-css@5.3.3)(cssnano@5.1.15(postcss@8.5.15))(csso@4.2.0)(html-minifier-terser@6.1.0)(postcss@8.5.15)(uglify-js@3.19.3)): dependencies: - webpack: 5.107.1(postcss@8.5.15) + webpack: 5.107.1(clean-css@5.3.3)(cssnano@5.1.15(postcss@8.5.15))(csso@4.2.0)(html-minifier-terser@6.1.0)(postcss@8.5.15)(uglify-js@3.19.3) style-mod@4.1.3: {} @@ -13264,15 +13140,20 @@ snapshots: ansi-escapes: 4.3.2 supports-hyperlinks: 2.3.0 - terser-webpack-plugin@5.6.0(postcss@8.5.15)(webpack@5.107.1(postcss@8.5.15)): + terser-webpack-plugin@5.6.0(clean-css@5.3.3)(cssnano@5.1.15(postcss@8.5.15))(csso@4.2.0)(html-minifier-terser@6.1.0)(postcss@8.5.15)(uglify-js@3.19.3)(webpack@5.107.1(clean-css@5.3.3)(cssnano@5.1.15(postcss@8.5.15))(csso@4.2.0)(html-minifier-terser@6.1.0)(postcss@8.5.15)(uglify-js@3.19.3)): dependencies: '@jridgewell/trace-mapping': 0.3.31 jest-worker: 27.5.1 schema-utils: 4.3.3 terser: 5.48.0 - webpack: 5.107.1(postcss@8.5.15) + webpack: 5.107.1(clean-css@5.3.3)(cssnano@5.1.15(postcss@8.5.15))(csso@4.2.0)(html-minifier-terser@6.1.0)(postcss@8.5.15)(uglify-js@3.19.3) optionalDependencies: + clean-css: 5.3.3 + cssnano: 5.1.15(postcss@8.5.15) + csso: 4.2.0 + html-minifier-terser: 6.1.0 postcss: 8.5.15 + uglify-js: 3.19.3 terser@5.48.0: dependencies: @@ -13303,10 +13184,6 @@ snapshots: thunky@1.1.0: {} - tiny-invariant@1.3.3: {} - - tiny-warning@1.0.3: {} - tinyglobby@0.2.16: dependencies: fdir: 6.5.0(picomatch@4.0.4) @@ -13343,24 +13220,6 @@ snapshots: ts-interface-checker@0.1.13: {} - ts-jest@29.4.12(@babel/core@7.29.7)(@jest/types@29.6.3)(jest-util@29.7.0)(jest@27.5.1)(typescript@4.9.5): - dependencies: - bs-logger: 0.2.6 - fast-json-stable-stringify: 2.1.0 - handlebars: 4.7.9 - jest: 27.5.1 - json5: 2.2.3 - lodash.memoize: 4.1.2 - make-error: 1.3.6 - semver: 7.8.5 - type-fest: 4.41.0 - typescript: 4.9.5 - yargs-parser: 21.1.1 - optionalDependencies: - '@babel/core': 7.29.7 - '@jest/types': 29.6.3 - jest-util: 29.7.0 - tsconfig-paths@3.15.0: dependencies: '@types/json5': 0.0.29 @@ -13391,7 +13250,8 @@ snapshots: type-fest@0.21.3: {} - type-fest@4.41.0: {} + type-fest@4.41.0: + optional: true type-is@1.6.18: dependencies: @@ -13453,8 +13313,6 @@ snapshots: undici-types@6.21.0: {} - undici@7.25.0: {} - unicode-canonical-property-names-ecmascript@2.0.1: {} unicode-match-property-ecmascript@2.0.0: @@ -13516,8 +13374,6 @@ snapshots: convert-source-map: 1.9.0 source-map: 0.7.6 - value-equal@1.0.1: {} - vary@1.1.2: {} w3c-hr-time@1.0.2: @@ -13557,16 +13413,16 @@ snapshots: webidl-conversions@7.0.0: {} - webpack-dev-middleware@5.3.4(webpack@5.107.1(postcss@8.5.15)): + webpack-dev-middleware@5.3.4(webpack@5.107.1(clean-css@5.3.3)(cssnano@5.1.15(postcss@8.5.15))(csso@4.2.0)(html-minifier-terser@6.1.0)(postcss@8.5.15)(uglify-js@3.19.3)): dependencies: colorette: 2.0.20 memfs: 3.5.3 mime-types: 2.1.35 range-parser: 1.2.1 schema-utils: 4.3.3 - webpack: 5.107.1(postcss@8.5.15) + webpack: 5.107.1(clean-css@5.3.3)(cssnano@5.1.15(postcss@8.5.15))(csso@4.2.0)(html-minifier-terser@6.1.0)(postcss@8.5.15)(uglify-js@3.19.3) - webpack-dev-server@4.15.2(webpack@5.107.1(postcss@8.5.15)): + webpack-dev-server@4.15.2(debug@4.4.3(supports-color@8.1.1))(supports-color@8.1.1)(webpack@5.107.1(clean-css@5.3.3)(cssnano@5.1.15(postcss@8.5.15))(csso@4.2.0)(html-minifier-terser@6.1.0)(postcss@8.5.15)(uglify-js@3.19.3)): dependencies: '@types/bonjour': 3.5.13 '@types/connect-history-api-fallback': 1.5.4 @@ -13579,13 +13435,13 @@ snapshots: bonjour-service: 1.4.0 chokidar: 3.6.0 colorette: 2.0.20 - compression: 1.8.1 + compression: 1.8.1(supports-color@8.1.1) connect-history-api-fallback: 2.0.0 default-gateway: 6.0.3 - express: 4.22.2 + express: 4.22.2(supports-color@8.1.1) graceful-fs: 4.2.11 html-entities: 2.6.0 - http-proxy-middleware: 2.0.9(@types/express@4.17.25) + http-proxy-middleware: 2.0.9(@types/express@4.17.25)(debug@4.4.3(supports-color@8.1.1)) ipaddr.js: 2.4.0 launch-editor: 2.13.2 open: 8.4.2 @@ -13593,23 +13449,23 @@ snapshots: rimraf: 3.0.2 schema-utils: 4.3.3 selfsigned: 2.4.1 - serve-index: 1.9.2 + serve-index: 1.9.2(supports-color@8.1.1) sockjs: 0.3.24 - spdy: 4.0.2 - webpack-dev-middleware: 5.3.4(webpack@5.107.1(postcss@8.5.15)) + spdy: 4.0.2(supports-color@8.1.1) + webpack-dev-middleware: 5.3.4(webpack@5.107.1(clean-css@5.3.3)(cssnano@5.1.15(postcss@8.5.15))(csso@4.2.0)(html-minifier-terser@6.1.0)(postcss@8.5.15)(uglify-js@3.19.3)) ws: 8.21.0 optionalDependencies: - webpack: 5.107.1(postcss@8.5.15) + webpack: 5.107.1(clean-css@5.3.3)(cssnano@5.1.15(postcss@8.5.15))(csso@4.2.0)(html-minifier-terser@6.1.0)(postcss@8.5.15)(uglify-js@3.19.3) transitivePeerDependencies: - bufferutil - debug - supports-color - utf-8-validate - webpack-manifest-plugin@4.1.1(webpack@5.107.1(postcss@8.5.15)): + webpack-manifest-plugin@4.1.1(webpack@5.107.1(clean-css@5.3.3)(cssnano@5.1.15(postcss@8.5.15))(csso@4.2.0)(html-minifier-terser@6.1.0)(postcss@8.5.15)(uglify-js@3.19.3)): dependencies: tapable: 2.3.3 - webpack: 5.107.1(postcss@8.5.15) + webpack: 5.107.1(clean-css@5.3.3)(cssnano@5.1.15(postcss@8.5.15))(csso@4.2.0)(html-minifier-terser@6.1.0)(postcss@8.5.15)(uglify-js@3.19.3) webpack-sources: 2.3.1 webpack-sources@1.4.3: @@ -13624,7 +13480,7 @@ snapshots: webpack-sources@3.5.0: {} - webpack@5.107.1(postcss@8.5.15): + webpack@5.107.1(clean-css@5.3.3)(cssnano@5.1.15(postcss@8.5.15))(csso@4.2.0)(html-minifier-terser@6.1.0)(postcss@8.5.15)(uglify-js@3.19.3): dependencies: '@types/estree': 1.0.9 '@types/json-schema': 7.0.15 @@ -13646,7 +13502,7 @@ snapshots: neo-async: 2.6.2 schema-utils: 4.3.3 tapable: 2.3.3 - terser-webpack-plugin: 5.6.0(postcss@8.5.15)(webpack@5.107.1(postcss@8.5.15)) + terser-webpack-plugin: 5.6.0(clean-css@5.3.3)(cssnano@5.1.15(postcss@8.5.15))(csso@4.2.0)(html-minifier-terser@6.1.0)(postcss@8.5.15)(uglify-js@3.19.3)(webpack@5.107.1(clean-css@5.3.3)(cssnano@5.1.15(postcss@8.5.15))(csso@4.2.0)(html-minifier-terser@6.1.0)(postcss@8.5.15)(uglify-js@3.19.3)) watchpack: 2.5.1 webpack-sources: 3.5.0 transitivePeerDependencies: @@ -13675,16 +13531,10 @@ snapshots: dependencies: iconv-lite: 0.4.24 - whatwg-encoding@3.1.1: - dependencies: - iconv-lite: 0.6.3 - whatwg-fetch@3.6.20: {} whatwg-mimetype@2.3.0: {} - whatwg-mimetype@4.0.0: {} - whatwg-url@5.0.0: dependencies: tr46: 0.0.3 @@ -13753,8 +13603,6 @@ snapshots: word-wrap@1.2.5: {} - wordwrap@1.0.0: {} - workbox-background-sync@6.6.0: dependencies: idb: 7.1.1 @@ -13764,13 +13612,13 @@ snapshots: dependencies: workbox-core: 6.6.0 - workbox-build@6.6.0(@types/babel__core@7.20.5): + workbox-build@6.6.0(@types/babel__core@7.20.5)(supports-color@8.1.1): dependencies: '@apideck/better-ajv-errors': 0.3.7(ajv@8.20.0) - '@babel/core': 7.29.7 - '@babel/preset-env': 7.29.7(@babel/core@7.29.7) + '@babel/core': 7.29.7(supports-color@8.1.1) + '@babel/preset-env': 7.29.7(@babel/core@7.29.7(supports-color@8.1.1))(supports-color@8.1.1) '@babel/runtime': 7.29.7 - '@rollup/plugin-babel': 5.3.1(@babel/core@7.29.7)(@types/babel__core@7.20.5)(rollup@2.80.0) + '@rollup/plugin-babel': 5.3.1(@babel/core@7.29.7(supports-color@8.1.1))(@types/babel__core@7.20.5)(rollup@2.80.0)(supports-color@8.1.1) '@rollup/plugin-node-resolve': 11.2.1(rollup@2.80.0) '@rollup/plugin-replace': 2.4.2(rollup@2.80.0) '@surma/rollup-plugin-off-main-thread': 2.2.3 @@ -13863,14 +13711,14 @@ snapshots: workbox-sw@6.6.0: {} - workbox-webpack-plugin@6.6.0(@types/babel__core@7.20.5)(webpack@5.107.1(postcss@8.5.15)): + workbox-webpack-plugin@6.6.0(@types/babel__core@7.20.5)(supports-color@8.1.1)(webpack@5.107.1(clean-css@5.3.3)(cssnano@5.1.15(postcss@8.5.15))(csso@4.2.0)(html-minifier-terser@6.1.0)(postcss@8.5.15)(uglify-js@3.19.3)): dependencies: fast-json-stable-stringify: 2.1.0 pretty-bytes: 5.6.0 upath: 1.2.0 - webpack: 5.107.1(postcss@8.5.15) + webpack: 5.107.1(clean-css@5.3.3)(cssnano@5.1.15(postcss@8.5.15))(csso@4.2.0)(html-minifier-terser@6.1.0)(postcss@8.5.15)(uglify-js@3.19.3) webpack-sources: 1.4.3 - workbox-build: 6.6.0(@types/babel__core@7.20.5) + workbox-build: 6.6.0(@types/babel__core@7.20.5)(supports-color@8.1.1) transitivePeerDependencies: - '@types/babel__core' - supports-color @@ -13911,8 +13759,6 @@ snapshots: yargs-parser@20.2.9: {} - yargs-parser@21.1.1: {} - yargs@16.2.0: dependencies: cliui: 7.0.4 diff --git a/web/ui/react-app/pnpm-workspace.yaml b/web/ui/react-app/pnpm-workspace.yaml index 99636430890..a9830705693 100644 --- a/web/ui/react-app/pnpm-workspace.yaml +++ b/web/ui/react-app/pnpm-workspace.yaml @@ -2,6 +2,13 @@ # issues with conflicting dependencies. This is a temporary solution until the # new Mantine-based UI is fully integrated and the old app can be removed. packages: [] +overrides: + # Enzyme loads Cheerio before Jest setup; newer versions require TextDecoder. + enzyme>cheerio: 1.0.0-rc.12 +peerDependencyRules: + allowedVersions: + # Reactstrap 8 uses react-popper whose peer metadata predates React 18; interaction tests cover compatibility. + 'react-popper@1.3.11>react': ^18.0.0 allowBuilds: '@parcel/watcher': true core-js: true diff --git a/web/ui/react-app/src/App.test.tsx b/web/ui/react-app/src/App.test.tsx index 62f685c921a..24c70bc3d07 100755 --- a/web/ui/react-app/src/App.test.tsx +++ b/web/ui/react-app/src/App.test.tsx @@ -1,45 +1,77 @@ import * as React from 'react'; -import { shallow } from 'enzyme'; +import { render, screen, waitFor } from '@testing-library/react'; import App from './App'; -import Navigation from './Navbar'; -import { Container } from 'reactstrap'; -import { Route } from 'react-router-dom'; -import { - AgentPage, - AlertsPage, - ConfigPage, - FlagsPage, - RulesPage, - ServiceDiscoveryPage, - StatusPage, - TargetsPage, - TSDBStatusPage, - PanelListPage, -} from './pages'; + +jest.mock('./Navbar', () => { + const React = require('react'); + return () => React.createElement('nav', { 'data-testid': 'navigation' }); +}); + +jest.mock('./pages', () => { + const React = require('react'); + const page = (testID: string) => () => React.createElement('div', { 'data-testid': testID }); + + return { + AgentPage: page('agent-page'), + AlertsPage: page('alerts-page'), + ConfigPage: page('config-page'), + FlagsPage: page('flags-page'), + PanelListPage: page('graph-page'), + RulesPage: page('rules-page'), + ServiceDiscoveryPage: page('service-discovery-page'), + StatusPage: page('status-page'), + TargetsPage: page('targets-page'), + TSDBStatusPage: page('tsdb-status-page'), + }; +}); + +const renderApp = (path: string, agentMode = false): ReturnType => { + window.history.pushState({}, '', path); + return render(); +}; describe('App', () => { - const app = shallow(); + beforeEach(() => { + localStorage.clear(); + }); - it('navigates', () => { - expect(app.find(Navigation)).toHaveLength(1); + it.each([ + ['/agent', 'agent-page'], + ['/graph', 'graph-page'], + ['/alerts', 'alerts-page'], + ['/config', 'config-page'], + ['/flags', 'flags-page'], + ['/rules', 'rules-page'], + ['/service-discovery', 'service-discovery-page'], + ['/status', 'status-page'], + ['/targets', 'targets-page'], + ['/tsdb-status', 'tsdb-status-page'], + ])('renders the route at %s', (path, pageTestID) => { + const { container } = renderApp(path); + + expect(screen.getByTestId(pageTestID)).toBeTruthy(); + expect(screen.getByTestId('navigation')).toBeTruthy(); + expect(container.querySelector('.container-fluid')).not.toBeNull(); + }); + + it.each([ + ['/', false, '/graph', 'graph-page'], + ['/', true, '/agent', 'agent-page'], + ['/prometheus', false, '/prometheus/graph', 'graph-page'], + ['/prometheus', true, '/prometheus/agent', 'agent-page'], + ])('redirects %s in agent mode %s to %s', async (path, agentMode, expectedPath, pageTestID) => { + renderApp(path, agentMode); + + await waitFor(() => expect(window.location.pathname).toBe(expectedPath)); + expect(screen.getByTestId(pageTestID)).toBeTruthy(); }); - it('routes', () => { - [ - AgentPage, - AlertsPage, - ConfigPage, - FlagsPage, - RulesPage, - ServiceDiscoveryPage, - StatusPage, - TargetsPage, - TSDBStatusPage, - PanelListPage, - ].forEach((component) => { - const c = app.find(component); - expect(c).toHaveLength(1); - }); - expect(app.find(Route)).toHaveLength(10); - expect(app.find(Container)).toHaveLength(1); + + it.each([ + ['/prometheus/alerts', 'alerts-page'], + ['/prometheus/targets/', 'targets-page'], + ])('renders prefixed route %s', (path, pageTestID) => { + renderApp(path); + + expect(screen.getByTestId(pageTestID)).toBeTruthy(); }); }); diff --git a/web/ui/react-app/src/App.tsx b/web/ui/react-app/src/App.tsx index 31cf72ab00a..626ce7afaaa 100755 --- a/web/ui/react-app/src/App.tsx +++ b/web/ui/react-app/src/App.tsx @@ -2,7 +2,7 @@ import { FC } from 'react'; import { Container } from 'reactstrap'; import Navigation from './Navbar'; -import { BrowserRouter as Router, Redirect, Route, Switch } from 'react-router-dom'; +import { BrowserRouter as Router, Navigate, Route, Routes } from 'react-router-dom'; import { PathPrefixContext } from './contexts/PathPrefixContext'; import { ThemeContext, themeName, themeSetting } from './contexts/ThemeContext'; import { ReadyContext } from './contexts/ReadyContext'; @@ -81,43 +81,23 @@ const App: FC = ({ consolesLink, agentMode, ready }) => { - - + + } /> {/* NOTE: Any route added here needs to also be added to the list of React-handled router paths ("reactRouterPaths") in /web/web.go. */} - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + } /> + } /> + } /> + } /> + } /> + } /> + } /> + } /> + } /> + } /> + diff --git a/web/ui/react-app/src/Navbar.test.tsx b/web/ui/react-app/src/Navbar.test.tsx index fb22244c7a7..2f78ce93dba 100644 --- a/web/ui/react-app/src/Navbar.test.tsx +++ b/web/ui/react-app/src/Navbar.test.tsx @@ -1,30 +1,35 @@ import * as React from 'react'; -import { shallow } from 'enzyme'; +import { fireEvent, render, screen, waitFor } from '@testing-library/react'; +import { MemoryRouter, Route, Routes } from 'react-router-dom'; import Navigation from './Navbar'; -import { NavItem, NavLink } from 'reactstrap'; -describe('Navbar should contain console Link', () => { - it('with non-empty consoleslink', () => { - const app = shallow(); - expect( - app.contains( - - Consoles - - ) - ).toBeTruthy(); +const renderNavigation = (consolesLink: string | null): ReturnType => + render( + + + + } /> + + + ); + +describe('Navbar', () => { + it.each([ + ['/path/consoles', '/path/consoles'], + [null, null], + ])('renders consoles link %s', (consolesLink, expectedHref) => { + renderNavigation(consolesLink); + + const link = screen.queryByRole('link', { name: 'Consoles' }); + expect(link?.getAttribute('href') ?? null).toBe(expectedHref); }); -}); -describe('Navbar should not contain consoles link', () => { - it('with empty string in consolesLink', () => { - const app = shallow(); - expect( - app.contains( - - Consoles - - ) - ).toBeFalsy(); + it('opens the status dropdown and navigates with React Router', async () => { + renderNavigation(null); + + fireEvent.click(screen.getByText('Status')); + fireEvent.click(screen.getByText('Runtime & Build Information')); + + await waitFor(() => expect(screen.getByTestId('status-route')).toBeTruthy()); }); }); diff --git a/web/ui/react-app/src/components/Checkbox.tsx b/web/ui/react-app/src/components/Checkbox.tsx index e988628f628..10b407c8270 100644 --- a/web/ui/react-app/src/components/Checkbox.tsx +++ b/web/ui/react-app/src/components/Checkbox.tsx @@ -1,7 +1,8 @@ -import React, { FC, memo, CSSProperties } from 'react'; +import React, { FC, memo, CSSProperties, ReactNode } from 'react'; import { FormGroup, Label, Input, InputProps } from 'reactstrap'; interface CheckboxProps extends InputProps { + children?: ReactNode; wrapperStyles?: CSSProperties; } diff --git a/web/ui/react-app/src/components/ToggleMoreLess.tsx b/web/ui/react-app/src/components/ToggleMoreLess.tsx index 80abbcd1e9a..484ed1eda1b 100644 --- a/web/ui/react-app/src/components/ToggleMoreLess.tsx +++ b/web/ui/react-app/src/components/ToggleMoreLess.tsx @@ -1,7 +1,8 @@ -import React, { FC } from 'react'; +import React, { FC, ReactNode } from 'react'; import { Button } from 'reactstrap'; interface ToggleMoreLessProps { + children?: ReactNode; event(): void; showMore: boolean; } diff --git a/web/ui/react-app/src/hooks/useLocalStorage.test.tsx b/web/ui/react-app/src/hooks/useLocalStorage.test.tsx index 5b554263350..02405ef5ed7 100644 --- a/web/ui/react-app/src/hooks/useLocalStorage.test.tsx +++ b/web/ui/react-app/src/hooks/useLocalStorage.test.tsx @@ -1,7 +1,11 @@ import { useLocalStorage } from './useLocalStorage'; -import { renderHook, act } from '@testing-library/react-hooks'; +import { act, renderHook } from '@testing-library/react'; describe('useLocalStorage', () => { + beforeEach(() => { + localStorage.clear(); + }); + it('returns the initialState', () => { const initialState = { a: 1, b: 2 }; const { result } = renderHook(() => useLocalStorage('mystorage', initialState)); @@ -36,6 +40,6 @@ describe('useLocalStorage', () => { result.current[1](newValue); }); expect(spyStorage).toHaveBeenCalledTimes(1); - spyStorage.mockReset(); + spyStorage.mockRestore(); }); }); diff --git a/web/ui/react-app/src/index.tsx b/web/ui/react-app/src/index.tsx index 61a9ae083c6..405cd0e2b04 100755 --- a/web/ui/react-app/src/index.tsx +++ b/web/ui/react-app/src/index.tsx @@ -1,6 +1,6 @@ import './globals'; import React from 'react'; -import ReactDOM from 'react-dom'; +import { createRoot } from 'react-dom/client'; import App from './App'; import './themes/app.scss'; import './themes/light.scss'; @@ -25,7 +25,6 @@ if ( consolesLink = null; } -ReactDOM.render( - , - document.getElementById('root') +createRoot(document.getElementById('root')!).render( + ); diff --git a/web/ui/react-app/src/pages/alerts/AlertContents.tsx b/web/ui/react-app/src/pages/alerts/AlertContents.tsx index c5aed9183c2..4a13d295813 100644 --- a/web/ui/react-app/src/pages/alerts/AlertContents.tsx +++ b/web/ui/react-app/src/pages/alerts/AlertContents.tsx @@ -1,4 +1,4 @@ -import React, { FC, Fragment, useCallback, useEffect, useMemo, useState } from 'react'; +import React, { FC, Fragment, ReactNode, useCallback, useEffect, useMemo, useState } from 'react'; import { Badge, Col, Row } from 'reactstrap'; import CollapsibleAlertPanel from './CollapsibleAlertPanel'; import Checkbox from '../../components/Checkbox'; @@ -167,6 +167,7 @@ const AlertsContent: FC = ({ groups = [], statsCount }) => { }; interface GroupInfoProps { + children?: ReactNode; rules: Rule[]; } diff --git a/web/ui/react-app/src/pages/flags/__snapshots__/Flags.test.tsx.snap b/web/ui/react-app/src/pages/flags/__snapshots__/Flags.test.tsx.snap index 9796b2991ba..5821eca9fa7 100644 --- a/web/ui/react-app/src/pages/flags/__snapshots__/Flags.test.tsx.snap +++ b/web/ui/react-app/src/pages/flags/__snapshots__/Flags.test.tsx.snap @@ -43,14 +43,6 @@ exports[`Flags should match snapshot 1`] = ` Flag diff --git a/web/ui/react-app/src/pages/graph/HistogramChart.test.tsx b/web/ui/react-app/src/pages/graph/HistogramChart.test.tsx index e9529282b1a..91d76824d22 100644 --- a/web/ui/react-app/src/pages/graph/HistogramChart.test.tsx +++ b/web/ui/react-app/src/pages/graph/HistogramChart.test.tsx @@ -19,6 +19,7 @@ jest.spyOn(global.Intl, 'NumberFormat').mockImplementation(() => ({ describe('HistogramChart', () => { let wrapper: ReactWrapper; + let container: HTMLDivElement; const histogramDataLinear: Histogram = { count: '30', @@ -69,6 +70,8 @@ describe('HistogramChart', () => { }; beforeEach(() => { + container = document.createElement('div'); + document.body.appendChild(container); mockFormat.mockClear(); mockResolvedOptions.mockClear(); mockFormatToParts.mockClear(); @@ -80,29 +83,38 @@ describe('HistogramChart', () => { if (wrapper && wrapper.exists()) { wrapper.unmount(); } + container.remove(); }); it('renders without crashing', () => { - wrapper = mount(); + wrapper = mount(, { + attachTo: container, + }); expect(wrapper.find('.histogram-y-wrapper').exists()).toBe(true); expect(wrapper.find('.histogram-container').exists()).toBe(true); }); it('renders "No data" when buckets are empty', () => { - wrapper = mount(); + wrapper = mount(, { + attachTo: container, + }); expect(wrapper.text()).toContain('No data'); expect(wrapper.find('.histogram-container').exists()).toBe(false); }); it('renders "No data" when buckets are null', () => { - wrapper = mount(); + wrapper = mount(, { + attachTo: container, + }); expect(wrapper.text()).toContain('No data'); expect(wrapper.find('.histogram-container').exists()).toBe(false); }); describe('Linear Scale', () => { beforeEach(() => { - wrapper = mount(); + wrapper = mount(, { + attachTo: container, + }); }); it('renders the correct number of buckets', () => { @@ -163,7 +175,8 @@ describe('HistogramChart', () => { describe('Exponential Scale', () => { beforeEach(() => { wrapper = mount( - + , + { attachTo: container } ); }); @@ -216,7 +229,6 @@ describe('HistogramChart', () => { expect(parseFloat(b2.prop('style')?.width as string)).toBeGreaterThan(0); const b3 = buckets.at(2); - const b3Height = (50 / countMax) * 100; expect(b3.find('.histogram-bucket').prop('style')).toHaveProperty('height', '100%'); expect(parseFloat(b3.prop('style')?.left as string)).toBeGreaterThan(0); expect(parseFloat(b3.prop('style')?.width as string)).toBeGreaterThan(0); @@ -232,8 +244,10 @@ describe('HistogramChart', () => { }); it('handles zero-crossing bucket correctly in exponential scale', () => { + wrapper.unmount(); wrapper = mount( - + , + { attachTo: container } ); const buckets = wrapper.find('.histogram-bucket-slot'); const countMax = 15; diff --git a/web/ui/react-app/src/pages/targets/ScrapePoolList.test.tsx b/web/ui/react-app/src/pages/targets/ScrapePoolList.test.tsx index 5952dc3490c..091256cde40 100644 --- a/web/ui/react-app/src/pages/targets/ScrapePoolList.test.tsx +++ b/web/ui/react-app/src/pages/targets/ScrapePoolList.test.tsx @@ -32,6 +32,10 @@ describe('ScrapePoolList', () => { mock = fetchMock.mockResponse(JSON.stringify(sampleApiResponse)); }); + afterEach(() => { + document.querySelectorAll('[id^="series-labels-"], [id^="scrape-duration-"]').forEach((element) => element.remove()); + }); + it('renders a table', async () => { await act(async () => { scrapePoolList = mount( @@ -53,6 +57,33 @@ describe('ScrapePoolList', () => { expect(panel).toHaveLength(1); }); }); + + it('opens the scrape pool dropdown and selects a pool', async () => { + const onPoolSelect = jest.fn(); + await act(async () => { + scrapePoolList = mount( + + + + ); + }); + scrapePoolList.update(); + + scrapePoolList.find('button.dropdown-toggle').simulate('click'); + scrapePoolList.update(); + + const menu = scrapePoolList.find('div.dropdown-menu.show'); + expect(menu).toHaveLength(1); + const nodeExporterItem = menu.find('button.dropdown-item').filterWhere((item) => item.text() === 'node_exporter'); + expect(nodeExporterItem).toHaveLength(1); + + nodeExporterItem.simulate('click'); + expect(onPoolSelect).toHaveBeenCalledWith('node_exporter'); + }); }); describe('when an error is returned', () => { diff --git a/web/ui/react-app/src/pages/targets/TargetScrapeDuration.test.tsx b/web/ui/react-app/src/pages/targets/TargetScrapeDuration.test.tsx new file mode 100644 index 00000000000..7917bdf5a70 --- /dev/null +++ b/web/ui/react-app/src/pages/targets/TargetScrapeDuration.test.tsx @@ -0,0 +1,18 @@ +import * as React from 'react'; +import { fireEvent, render, screen } from '@testing-library/react'; +import TargetScrapeDuration from './TargetScrapeDuration'; + +describe('TargetScrapeDuration', () => { + it('opens the scrape duration tooltip', async () => { + render(); + + const target = document.getElementById('scrape-duration-prometheus/test-2'); + expect(target).not.toBeNull(); + + fireEvent.mouseOver(target!); + + expect(await screen.findByText('Interval: 15s')).toBeTruthy(); + expect(screen.getByText('Timeout: 10s')).toBeTruthy(); + expect(document.querySelector('.tooltip.show')).not.toBeNull(); + }); +}); diff --git a/web/ui/react-app/src/setupTests.ts b/web/ui/react-app/src/setupTests.ts index f4d3d39b614..578048ad8c6 100644 --- a/web/ui/react-app/src/setupTests.ts +++ b/web/ui/react-app/src/setupTests.ts @@ -1,10 +1,16 @@ import { configure } from 'enzyme'; -import Adapter from '@wojtekmaj/enzyme-adapter-react-17'; +import Adapter from '@cfaester/enzyme-adapter-react-18'; import { GlobalWithFetchMock } from 'jest-fetch-mock'; +import { TextDecoder, TextEncoder } from 'util'; import 'mutationobserver-shim'; // Needed for CodeMirror. import './globals'; import 'jest-canvas-mock'; +Object.defineProperties(global, { + TextDecoder: { value: TextDecoder }, + TextEncoder: { value: TextEncoder }, +}); + configure({ adapter: new Adapter() }); const customGlobal: GlobalWithFetchMock = global as GlobalWithFetchMock; customGlobal.fetch = require('jest-fetch-mock'); diff --git a/web/ui/react-app/src/utils/utils.test.ts b/web/ui/react-app/src/utils/utils.test.ts index 61fcd733ab6..d4ae0babb06 100644 --- a/web/ui/react-app/src/utils/utils.test.ts +++ b/web/ui/react-app/src/utils/utils.test.ts @@ -340,7 +340,7 @@ describe('Utils', () => { ); }); it('url-encodes PromQL', () => { - expect(createExpressionLink('ALERTS{alertname="HighCPU"}')).toEqual( + expect(createExpressionLink('ALERTS{alertname="High CPU"}')).toEqual( `../graph?g0.expr=ALERTS%7Balertname%3D%22High%20CPU%22%7D&g0.tab=1&g0.display_mode=${GraphDisplayMode.Lines}&g0.show_exemplars=0&g0.range_input=1h` ); }); diff --git a/web/web.go b/web/web.go index b7ad8e3b397..29c27e0120d 100644 --- a/web/web.go +++ b/web/web.go @@ -61,6 +61,7 @@ import ( "github.com/prometheus/prometheus/template" "github.com/prometheus/prometheus/util/features" "github.com/prometheus/prometheus/util/httputil" + "github.com/prometheus/prometheus/util/memorylimiter" "github.com/prometheus/prometheus/util/netconnlimit" "github.com/prometheus/prometheus/util/notifications" api_v1 "github.com/prometheus/prometheus/web/api/v1" @@ -322,6 +323,9 @@ type Options struct { // Parser is the PromQL parser used for parsing query expressions. Parser parser.Parser + + // MemoryLimiter is used to reject ingestion/queries under memory pressure. + MemoryLimiter memorylimiter.MemoryLimiter } // New initializes a new web Handler. @@ -440,6 +444,9 @@ func New(logger *slog.Logger, o *Options) *Handler { }, o.Parser, ) + if o.MemoryLimiter != nil { + h.apiV1.SetMemoryLimiter(o.MemoryLimiter) + } if r := o.FeatureRegistry; r != nil { // Set dynamic API features (based on configuration).