From 18db46049803b8d591b8af65f2633e52af4cbf5f Mon Sep 17 00:00:00 2001 From: Rohit Behera <126186063+r0h1tb@users.noreply.github.com> Date: Mon, 3 Aug 2026 17:27:02 +0530 Subject: [PATCH 01/72] discovery/aws: don't panic on Lightsail instances with absent optional fields Lightsail SD guarded only PrivateIpAddress before building the label set, then dereferenced six more pointers unconditionally: 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), Every one of those is optional in the AWS API. Location is a *ResourceLocation and State an *InstanceState, so those two chain through a second pointer each. If the API omits any of them the refresh goroutine panics with a nil pointer dereference and takes the whole Prometheus process down, rather than degrading the single target. Each label is now emitted only when its source field is present, matching the guarding already used throughout elasticache.go. An instance that carries nothing but a private IP still produces a scrapeable target. Adds discovery/aws/lightsail_test.go; the package had no Lightsail coverage, which is why this went unnoticed. Without the fix TestLightsailRefreshAllOptionalFieldsNil panics at lightsail.go:262. Signed-off-by: Rohit Behera <126186063+r0h1tb@users.noreply.github.com> --- discovery/aws/lightsail.go | 32 ++++-- discovery/aws/lightsail_test.go | 181 ++++++++++++++++++++++++++++++++ 2 files changed, 205 insertions(+), 8 deletions(-) create mode 100644 discovery/aws/lightsail_test.go 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) + } +} From 47b37f267d8ca2962d043d1f70d0a25af0bd1047 Mon Sep 17 00:00:00 2001 From: Minh Vu Date: Tue, 4 Aug 2026 19:16:24 +0200 Subject: [PATCH 02/72] discovery/aws: avoid panic on truncated ElastiCache ARNs Signed-off-by: Minh Vu --- discovery/aws/elasticache.go | 2 +- discovery/aws/elasticache_test.go | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/discovery/aws/elasticache.go b/discovery/aws/elasticache.go index 7aa1090cb01..ab2b0019bfd 100644 --- a/discovery/aws/elasticache.go +++ b/discovery/aws/elasticache.go @@ -600,7 +600,7 @@ func splitCacheDeploymentOptions(caches []string) (serverlessCacheIDs, cacheClus continue } parts := strings.Split(cacheARN, ":") - if len(parts) < 6 { + if len(parts) < 7 { continue } resourceType := parts[5] diff --git a/discovery/aws/elasticache_test.go b/discovery/aws/elasticache_test.go index 646c5d2a81d..3d898287c8c 100644 --- a/discovery/aws/elasticache_test.go +++ b/discovery/aws/elasticache_test.go @@ -582,6 +582,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, From 5a35c2c1f26b97cf2fb41788c62658f0dc130e1c Mon Sep 17 00:00:00 2001 From: Minh Vu Date: Thu, 6 Aug 2026 17:37:56 +0200 Subject: [PATCH 03/72] discovery/aws: log invalid ElastiCache ARNs Signed-off-by: Minh Vu --- discovery/aws/elasticache.go | 5 +++-- discovery/aws/elasticache_test.go | 3 ++- 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/discovery/aws/elasticache.go b/discovery/aws/elasticache.go index ab2b0019bfd..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) < 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 3d898287c8c..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" @@ -612,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") From 92ac951e0c4275bd818217e9dae71e8d10000805 Mon Sep 17 00:00:00 2001 From: Raj Date: Tue, 14 Jul 2026 16:43:20 -0500 Subject: [PATCH 04/72] discovery/aws: add test exposing MSK panic on nil Provisioned fields Serverless MSK clusters have no Provisioned configuration, and provisioned clusters without Open Monitoring have a nil OpenMonitoring field. The refresh label building dereferences both without checking, crashing Prometheus. Exposes #19184 Signed-off-by: Raj --- discovery/aws/msk_test.go | 134 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 134 insertions(+) diff --git a/discovery/aws/msk_test.go b/discovery/aws/msk_test.go index 725d3eeabd8..3fe913e2781 100644 --- a/discovery/aws/msk_test.go +++ b/discovery/aws/msk_test.go @@ -507,6 +507,140 @@ func TestMSKDiscoveryRefresh(t *testing.T) { }, }, }, + { + name: "ServerlessClusterWithoutProvisionedConfig", + 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"}, + }, + expected: []*targetgroup.Group{ + { + Source: "us-west-2", + Targets: []model.LabelSet{ + { + model.AddressLabel: model.LabelValue("b-2.serverless-cluster.def456.kafka.us-west-2.amazonaws.com:80"), + "__meta_msk_cluster_name": model.LabelValue("serverless-cluster"), + "__meta_msk_cluster_arn": model.LabelValue("arn:aws:kafka:us-west-2:123456789012:cluster/serverless-cluster/def-456"), + "__meta_msk_cluster_state": model.LabelValue("ACTIVE"), + "__meta_msk_cluster_type": model.LabelValue("SERVERLESS"), + "__meta_msk_cluster_version": model.LabelValue("1.0.0"), + "__meta_msk_node_type": model.LabelValue("BROKER"), + "__meta_msk_node_arn": model.LabelValue("arn:aws:kafka:us-west-2:123456789012:node/broker-2"), + "__meta_msk_node_added_time": model.LabelValue("2023-01-01T00:00:00Z"), + "__meta_msk_node_instance_type": model.LabelValue("kafka.m5.xlarge"), + "__meta_msk_node_attached_eni": model.LabelValue("eni-67890"), + "__meta_msk_broker_id": model.LabelValue("2"), + "__meta_msk_broker_client_subnet": model.LabelValue("subnet-67890"), + "__meta_msk_broker_client_vpc_ip": model.LabelValue("10.0.2.100"), + "__meta_msk_broker_endpoint_index": model.LabelValue("0"), + }, + }, + }, + }, + }, + { + 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{ From 0b1c4571d3c21a8d8adc556b9d32f361a96b88f4 Mon Sep 17 00:00:00 2001 From: Raj Date: Tue, 14 Jul 2026 16:47:15 -0500 Subject: [PATCH 05/72] discovery/aws: fix MSK panic on clusters without provisioned config Serverless MSK clusters return a nil Provisioned field and provisioned clusters without Open Monitoring return a nil OpenMonitoring field. The refresh label building dereferenced both unconditionally, crashing the whole Prometheus process during service discovery. Guard the dereferences and omit the affected labels when the configuration is absent. Fixes #19184 Signed-off-by: Raj --- discovery/aws/msk.go | 41 ++++++++++++++++++++++++++++------------- 1 file changed, 28 insertions(+), 13 deletions(-) diff --git a/discovery/aws/msk.go b/discovery/aws/msk.go index 14616f84405..84685989c17 100644 --- a/discovery/aws/msk.go +++ b/discovery/aws/msk.go @@ -423,18 +423,28 @@ func (d *MSKDiscovery) refresh(ctx context.Context) ([]*targetgroup.Group, error defer wg.Done() for _, node := range nodes { labels := model.LabelSet{ - mskLabelClusterName: model.LabelValue(aws.ToString(cluster.ClusterName)), - mskLabelClusterARN: model.LabelValue(aws.ToString(cluster.ClusterArn)), - mskLabelClusterState: model.LabelValue(string(cluster.State)), - mskLabelClusterType: model.LabelValue(string(cluster.ClusterType)), - mskLabelClusterVersion: model.LabelValue(aws.ToString(cluster.CurrentVersion)), - 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)), - mskLabelClusterKafkaVersion: model.LabelValue(aws.ToString(cluster.Provisioned.CurrentBrokerSoftwareInfo.KafkaVersion)), + mskLabelClusterName: model.LabelValue(aws.ToString(cluster.ClusterName)), + mskLabelClusterARN: model.LabelValue(aws.ToString(cluster.ClusterArn)), + mskLabelClusterState: model.LabelValue(string(cluster.State)), + mskLabelClusterType: model.LabelValue(string(cluster.ClusterType)), + mskLabelClusterVersion: model.LabelValue(aws.ToString(cluster.CurrentVersion)), + mskLabelNodeARN: model.LabelValue(aws.ToString(node.NodeARN)), + mskLabelNodeAddedTime: model.LabelValue(aws.ToString(node.AddedToClusterTime)), + mskLabelNodeInstanceType: model.LabelValue(aws.ToString(node.InstanceType)), + } + + // Serverless clusters have no Provisioned configuration, and + // clusters without Open Monitoring have a nil OpenMonitoring, + // so the corresponding labels are omitted. + if provisioned := cluster.Provisioned; provisioned != nil { + if info := provisioned.CurrentBrokerSoftwareInfo; info != nil { + labels[mskLabelClusterConfigurationARN] = model.LabelValue(aws.ToString(info.ConfigurationArn)) + labels[mskLabelClusterConfigurationRevision] = model.LabelValue(strconv.FormatInt(aws.ToInt64(info.ConfigurationRevision), 10)) + labels[mskLabelClusterKafkaVersion] = model.LabelValue(aws.ToString(info.KafkaVersion)) + } + if om := 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 { @@ -448,7 +458,12 @@ 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)) + if provisioned := cluster.Provisioned; provisioned != nil && + provisioned.OpenMonitoring != nil && + provisioned.OpenMonitoring.Prometheus != nil && + provisioned.OpenMonitoring.Prometheus.NodeExporter != nil { + labels[mskLabelBrokerNodeExporterEnabled] = model.LabelValue(strconv.FormatBool(aws.ToBool(provisioned.OpenMonitoring.Prometheus.NodeExporter.EnabledInBroker))) + } for idx, endpoint := range node.BrokerNodeInfo.Endpoints { endpointLabels := labels.Clone() From 97f3bfcc79366edfc3f768847adde8e463904cd7 Mon Sep 17 00:00:00 2001 From: Raj Date: Wed, 15 Jul 2026 09:27:58 -0500 Subject: [PATCH 06/72] discovery/aws: skip non-provisioned MSK clusters in describeClusters Serverless clusters do not expose broker nodes and are already excluded from ListClustersV2 by the PROVISIONED filter, so an explicitly configured serverless cluster ARN is now skipped with a warning instead of being processed. Also document that the JMX and node exporter labels are absent, not false, when Open Monitoring is not enabled. Suggested by @matt-gp in the PR review. Signed-off-by: Raj --- discovery/aws/msk.go | 6 +++ discovery/aws/msk_test.go | 63 +++++++++++++++++++---------- docs/configuration/configuration.md | 6 +-- 3 files changed, 51 insertions(+), 24 deletions(-) diff --git a/discovery/aws/msk.go b/discovery/aws/msk.go index 84685989c17..96f5726822f 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() diff --git a/discovery/aws/msk_test.go b/discovery/aws/msk_test.go index 3fe913e2781..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, @@ -508,7 +545,7 @@ func TestMSKDiscoveryRefresh(t *testing.T) { }, }, { - name: "ServerlessClusterWithoutProvisionedConfig", + name: "ServerlessClusterProducesNoTargets", mskData: &mskDataStore{ region: "us-west-2", clusters: []types.Cluster{ @@ -544,28 +581,11 @@ func TestMSKDiscoveryRefresh(t *testing.T) { 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", - Targets: []model.LabelSet{ - { - model.AddressLabel: model.LabelValue("b-2.serverless-cluster.def456.kafka.us-west-2.amazonaws.com:80"), - "__meta_msk_cluster_name": model.LabelValue("serverless-cluster"), - "__meta_msk_cluster_arn": model.LabelValue("arn:aws:kafka:us-west-2:123456789012:cluster/serverless-cluster/def-456"), - "__meta_msk_cluster_state": model.LabelValue("ACTIVE"), - "__meta_msk_cluster_type": model.LabelValue("SERVERLESS"), - "__meta_msk_cluster_version": model.LabelValue("1.0.0"), - "__meta_msk_node_type": model.LabelValue("BROKER"), - "__meta_msk_node_arn": model.LabelValue("arn:aws:kafka:us-west-2:123456789012:node/broker-2"), - "__meta_msk_node_added_time": model.LabelValue("2023-01-01T00:00:00Z"), - "__meta_msk_node_instance_type": model.LabelValue("kafka.m5.xlarge"), - "__meta_msk_node_attached_eni": model.LabelValue("eni-67890"), - "__meta_msk_broker_id": model.LabelValue("2"), - "__meta_msk_broker_client_subnet": model.LabelValue("subnet-67890"), - "__meta_msk_broker_client_vpc_ip": model.LabelValue("10.0.2.100"), - "__meta_msk_broker_endpoint_index": model.LabelValue("0"), - }, - }, }, }, }, @@ -1141,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/configuration/configuration.md b/docs/configuration/configuration.md index bb939c39bb6..93fc74a68c9 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` From a77998b5d7dab692858bd10aefcbb39e9edbb4c1 Mon Sep 17 00:00:00 2001 From: Raj Date: Wed, 15 Jul 2026 11:44:40 -0500 Subject: [PATCH 07/72] discovery/aws: drop redundant Provisioned nil checks in MSK labels Since describeClusters and listClusters both only return provisioned clusters now, Provisioned and CurrentBrokerSoftwareInfo are always set; only Open Monitoring remains optional. Suggested by @matt-gp in review. Signed-off-by: Raj --- discovery/aws/msk.go | 44 +++++++++++++++++++------------------------- 1 file changed, 19 insertions(+), 25 deletions(-) diff --git a/discovery/aws/msk.go b/discovery/aws/msk.go index 96f5726822f..dd1f8808c7d 100644 --- a/discovery/aws/msk.go +++ b/discovery/aws/msk.go @@ -429,28 +429,23 @@ func (d *MSKDiscovery) refresh(ctx context.Context) ([]*targetgroup.Group, error defer wg.Done() for _, node := range nodes { labels := model.LabelSet{ - mskLabelClusterName: model.LabelValue(aws.ToString(cluster.ClusterName)), - mskLabelClusterARN: model.LabelValue(aws.ToString(cluster.ClusterArn)), - mskLabelClusterState: model.LabelValue(string(cluster.State)), - mskLabelClusterType: model.LabelValue(string(cluster.ClusterType)), - mskLabelClusterVersion: model.LabelValue(aws.ToString(cluster.CurrentVersion)), - mskLabelNodeARN: model.LabelValue(aws.ToString(node.NodeARN)), - mskLabelNodeAddedTime: model.LabelValue(aws.ToString(node.AddedToClusterTime)), - mskLabelNodeInstanceType: model.LabelValue(aws.ToString(node.InstanceType)), + mskLabelClusterName: model.LabelValue(aws.ToString(cluster.ClusterName)), + mskLabelClusterARN: model.LabelValue(aws.ToString(cluster.ClusterArn)), + mskLabelClusterState: model.LabelValue(string(cluster.State)), + mskLabelClusterType: model.LabelValue(string(cluster.ClusterType)), + mskLabelClusterVersion: model.LabelValue(aws.ToString(cluster.CurrentVersion)), + mskLabelNodeARN: model.LabelValue(aws.ToString(node.NodeARN)), + mskLabelNodeAddedTime: model.LabelValue(aws.ToString(node.AddedToClusterTime)), + mskLabelNodeInstanceType: model.LabelValue(aws.ToString(node.InstanceType)), + mskLabelClusterConfigurationARN: model.LabelValue(aws.ToString(cluster.Provisioned.CurrentBrokerSoftwareInfo.ConfigurationArn)), + mskLabelClusterConfigurationRevision: model.LabelValue(strconv.FormatInt(aws.ToInt64(cluster.Provisioned.CurrentBrokerSoftwareInfo.ConfigurationRevision), 10)), + mskLabelClusterKafkaVersion: model.LabelValue(aws.ToString(cluster.Provisioned.CurrentBrokerSoftwareInfo.KafkaVersion)), } - // Serverless clusters have no Provisioned configuration, and - // clusters without Open Monitoring have a nil OpenMonitoring, - // so the corresponding labels are omitted. - if provisioned := cluster.Provisioned; provisioned != nil { - if info := provisioned.CurrentBrokerSoftwareInfo; info != nil { - labels[mskLabelClusterConfigurationARN] = model.LabelValue(aws.ToString(info.ConfigurationArn)) - labels[mskLabelClusterConfigurationRevision] = model.LabelValue(strconv.FormatInt(aws.ToInt64(info.ConfigurationRevision), 10)) - labels[mskLabelClusterKafkaVersion] = model.LabelValue(aws.ToString(info.KafkaVersion)) - } - if om := provisioned.OpenMonitoring; om != nil && om.Prometheus != nil && om.Prometheus.JmxExporter != nil { - labels[mskLabelClusterJmxExporterEnabled] = model.LabelValue(strconv.FormatBool(aws.ToBool(om.Prometheus.JmxExporter.EnabledInBroker))) - } + // 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 { @@ -464,11 +459,10 @@ 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)) - if provisioned := cluster.Provisioned; provisioned != nil && - provisioned.OpenMonitoring != nil && - provisioned.OpenMonitoring.Prometheus != nil && - provisioned.OpenMonitoring.Prometheus.NodeExporter != nil { - labels[mskLabelBrokerNodeExporterEnabled] = model.LabelValue(strconv.FormatBool(aws.ToBool(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 { From fe75845b680fa0daf5ee1f335321c0f4acf4463c Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Mon, 10 Aug 2026 07:58:03 +0200 Subject: [PATCH 08/72] chore(deps): update actions/setup-node action to v6.5.0 (#19359) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- .github/workflows/ci.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 3c9e28b8208..83d89fbc634 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -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" From ffc91368b730057dc80d9c6cd404e49dfc3d3163 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Mon, 10 Aug 2026 07:58:04 +0200 Subject: [PATCH 09/72] chore(deps): update actions/stale action to v10.4.0 (#19360) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- .github/workflows/stale.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) 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 From 961d3a70aa5d768e531386234225a8bacf254371 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Mon, 10 Aug 2026 07:58:16 +0200 Subject: [PATCH 10/72] chore(deps): update prometheus/promci action to v0.9.0 (#19361) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- .github/workflows/ci.yml | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 83d89fbc634..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 }} From 1abe68ddb2668051aca583309edcd8a2c0080f84 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Mon, 10 Aug 2026 07:58:59 +0200 Subject: [PATCH 11/72] fix(deps): update google.golang.org/protobuf digest to 644d026 (#19350) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- go.mod | 2 +- go.sum | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/go.mod b/go.mod index ad423b02ff6..1b1bb4fe2f8 100644 --- a/go.mod +++ b/go.mod @@ -101,7 +101,7 @@ require ( google.golang.org/api v0.290.0 google.golang.org/genproto/googleapis/api v0.0.0-20260724162435-b2f20204f0df 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 diff --git a/go.sum b/go.sum index 41661183200..3e826f59a84 100644 --- a/go.sum +++ b/go.sum @@ -727,8 +727,8 @@ google.golang.org/genproto/googleapis/rpc v0.0.0-20260720155508-bb71a54f79dc h1: google.golang.org/genproto/googleapis/rpc v0.0.0-20260720155508-bb71a54f79dc/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= From 2cb9c28f9b01464d0c5a0b2e32f11d31878ff3f7 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Mon, 10 Aug 2026 08:31:43 +0000 Subject: [PATCH 12/72] fix(deps): update module github.com/moby/moby/client to v0.5.1 (#19357) * fix(deps): update module github.com/moby/moby/client to v0.5.1 * build: bump minimum Go version to 1.25.10 --------- Signed-off-by: Arve Knudsen Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> Co-authored-by: Arve Knudsen --- compliance/go.mod | 2 +- documentation/examples/remote_storage/go.mod | 2 +- go.mod | 4 ++-- go.sum | 4 ++-- go.work | 2 +- internal/tools/go.mod | 2 +- web/ui/mantine-ui/src/promql/tools/go.mod | 2 +- 7 files changed, 9 insertions(+), 9 deletions(-) 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/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 1b1bb4fe2f8..94c52648ad3 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 @@ -51,7 +51,7 @@ require ( 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 diff --git a/go.sum b/go.sum index 3e826f59a84..decc71e735e 100644 --- a/go.sum +++ b/go.sum @@ -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= 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/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 From c2558acf085bda070a891d1159576aea73c0570b Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Mon, 10 Aug 2026 11:15:42 +0200 Subject: [PATCH 13/72] fix(deps): update google.golang.org/genproto/googleapis/api digest to c8921c7 (#19244) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- go.mod | 4 ++-- go.sum | 8 ++++---- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/go.mod b/go.mod index 94c52648ad3..cba46aa1f7d 100644 --- a/go.mod +++ b/go.mod @@ -99,7 +99,7 @@ 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.20260806062936-644d0267c26e k8s.io/api v0.35.3 @@ -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 decc71e735e..001a12bf665 100644 --- a/go.sum +++ b/go.sum @@ -721,10 +721,10 @@ 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.20260806062936-644d0267c26e h1:EIVWoj7hKWJiXy9OdaukBGcSR+NH3cGL/uswTzfvuec= From e61dfef4d3065cf0f5a441af6a7ec455fbe31ef2 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Mon, 10 Aug 2026 09:21:13 +0000 Subject: [PATCH 14/72] fix(deps): update aws go dependencies (#19355) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- go.mod | 40 ++++++++++++++--------------- go.sum | 80 +++++++++++++++++++++++++++++----------------------------- 2 files changed, 60 insertions(+), 60 deletions(-) diff --git a/go.mod b/go.mod index cba46aa1f7d..08bb5abaec7 100644 --- a/go.mod +++ b/go.mod @@ -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 @@ -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 diff --git a/go.sum b/go.sum index 001a12bf665..0b986607fba 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= From d7e984ebcea23a319c862e2b49e3cc4408727207 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Mon, 10 Aug 2026 09:24:25 +0000 Subject: [PATCH 15/72] fix(deps): update github.com/hashicorp/nomad/api digest to d78b9b5 (#19109) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- go.mod | 2 +- go.sum | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/go.mod b/go.mod index 08bb5abaec7..0948653097f 100644 --- a/go.mod +++ b/go.mod @@ -42,7 +42,7 @@ require ( 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 diff --git a/go.sum b/go.sum index 0b986607fba..e2aeb51c5d0 100644 --- a/go.sum +++ b/go.sum @@ -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= From 1a8d308f108aa3c37f26d73d4d50d6df616867eb Mon Sep 17 00:00:00 2001 From: Julius Volz Date: Tue, 4 Aug 2026 17:43:00 +0200 Subject: [PATCH 16/72] UI: Improve native histogram table formatting This fixes scroll issues in the native histogram buckets table and also improves the display by aligning the values better and adding a light background bar representing the bucket count. Signed-off-by: Julius Volz --- .../src/pages/query/DataTable.module.css | 14 ++++ .../mantine-ui/src/pages/query/DataTable.tsx | 79 +++++++++++-------- 2 files changed, 62 insertions(+), 31 deletions(-) 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; From 820e056b924311eea0034bcd6abd1a0d48f4eaae Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Mon, 10 Aug 2026 11:52:52 +0200 Subject: [PATCH 17/72] fix(deps): update module github.com/klauspost/compress to v1.19.2 (#19356) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- go.mod | 2 +- go.sum | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/go.mod b/go.mod index 0948653097f..ea6ef115a39 100644 --- a/go.mod +++ b/go.mod @@ -46,7 +46,7 @@ require ( 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 diff --git a/go.sum b/go.sum index e2aeb51c5d0..9f4c12ff1d0 100644 --- a/go.sum +++ b/go.sum @@ -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= From 8ca3b7bb90dc0c416cf577058d802d4dd492644d Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Mon, 10 Aug 2026 11:58:19 +0200 Subject: [PATCH 18/72] fix(deps): update github.com/google/pprof digest to ef3492d (#19347) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- go.mod | 2 +- go.sum | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/go.mod b/go.mod index ea6ef115a39..7bdfd31466d 100644 --- a/go.mod +++ b/go.mod @@ -37,7 +37,7 @@ 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 diff --git a/go.sum b/go.sum index 9f4c12ff1d0..a0aac7b8f29 100644 --- a/go.sum +++ b/go.sum @@ -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= From 65ca09d077273af620a4e230c87513848e7c5ef2 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Mon, 10 Aug 2026 10:14:00 +0000 Subject: [PATCH 19/72] fix(deps): update module github.com/scaleway/scaleway-sdk-go to v1.0.0-beta.37 (#19358) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- go.mod | 2 +- go.sum | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/go.mod b/go.mod index 7bdfd31466d..7dc4d0d460f 100644 --- a/go.mod +++ b/go.mod @@ -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 diff --git a/go.sum b/go.sum index a0aac7b8f29..67ab48e4f79 100644 --- a/go.sum +++ b/go.sum @@ -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= @@ -734,8 +734,8 @@ gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8 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= From a513fa0a32b388d8e3a952e0ca8f23791b81d9af Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Mon, 10 Aug 2026 14:41:34 +0200 Subject: [PATCH 20/72] chore(deps): update typescript-eslint monorepo to v8.66.0 (#19362) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- web/ui/pnpm-lock.yaml | 568 ++++++++++++++++++++++-------------------- 1 file changed, 291 insertions(+), 277 deletions(-) diff --git a/web/ui/pnpm-lock.yaml b/web/ui/pnpm-lock.yaml index 05d6109f3e7..431f970fbf4 100644 --- a/web/ui/pnpm-lock.yaml +++ b/web/ui/pnpm-lock.yaml @@ -13,19 +13,19 @@ 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 @@ -158,10 +158,10 @@ importers: devDependencies: '@eslint/compat': specifier: ^1.4.1 - version: 1.4.1(eslint@9.39.5) + version: 1.4.1(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 @@ -173,28 +173,28 @@ importers: version: 19.2.3(@types/react@19.2.17) '@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.23))) 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 @@ -212,7 +212,7 @@ importers: version: 6.4.3(@types/node@26.0.1)(sugarss@5.0.1(postcss@8.5.23)) 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.23))(supports-color@8.1.1) module/codemirror-promql: dependencies: @@ -240,10 +240,10 @@ importers: version: 6.43.6 '@eslint/compat': specifier: ^1.4.1 - version: 1.4.1(eslint@9.39.5) + version: 1.4.1(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,22 +258,22 @@ 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 @@ -294,7 +294,7 @@ importers: version: 16.0.3(rollup@4.62.3) 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 @@ -705,6 +705,12 @@ packages: cpu: [x64] os: [win32] + '@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 + '@eslint-community/eslint-utils@4.9.1': resolution: {integrity: sha512-phrYmNiYppR7znFEdqgfWHXR6NCkZEK7hwWDHZUjit/2/U0r6XvkDl0SYnoM51Hq7FhCGdLDT6zxCCOY1hexsQ==} engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} @@ -1313,63 +1319,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 +1670,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 +2270,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 +2665,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: @@ -3627,20 +3633,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 +3671,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 +3704,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 +3807,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 +3815,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 @@ -3987,23 +3993,28 @@ 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/eslint-utils@4.9.1(eslint@9.39.5(supports-color@8.1.1))': + dependencies: + 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@1.4.1(eslint@9.39.5(supports-color@8.1.1))': dependencies: '@eslint/core': 0.17.0 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 +4027,10 @@ snapshots: dependencies: '@types/json-schema': 7.0.15 - '@eslint/eslintrc@3.3.6': + '@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 @@ -4108,13 +4119,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 +4135,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 +4172,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 +4190,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 +4204,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 +4219,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 +4267,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 @@ -4667,74 +4678,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,20 +4753,20 @@ 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)': @@ -4857,11 +4868,11 @@ 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.23)))': 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 @@ -4965,25 +4976,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 +5003,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 +5043,7 @@ snapshots: dependencies: balanced-match: 1.0.2 - brace-expansion@5.0.6: + brace-expansion@5.0.9: dependencies: balanced-match: 4.0.4 @@ -5164,9 +5175,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 +5326,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 +5358,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.9.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 +5375,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 +5618,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 +5640,7 @@ snapshots: ignore@5.3.2: {} - ignore@7.0.5: {} + ignore@7.0.6: {} immer@11.1.8: {} @@ -5691,9 +5704,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 +5720,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 +5745,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 +5759,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 +5771,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 +5790,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 +5930,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 +5948,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 +5966,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 +5975,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 +5995,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 +6074,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 +6100,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 +6222,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: @@ -6793,12 +6806,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 +6820,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: {} @@ -6915,10 +6929,10 @@ 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.23))(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)) @@ -6949,7 +6963,7 @@ snapshots: fsevents: 2.3.3 sugarss: 5.0.1(postcss@8.5.23) - 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.23))(supports-color@8.1.1): dependencies: '@types/chai': 5.2.3 '@vitest/expect': 3.2.7 @@ -6960,7 +6974,7 @@ snapshots: '@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 @@ -6972,11 +6986,11 @@ snapshots: 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-node: 3.2.4(@types/node@26.0.1)(sugarss@5.0.1(postcss@8.5.23))(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 From 466c700ad2719056368fad38a2c15f78565606c8 Mon Sep 17 00:00:00 2001 From: zenador Date: Mon, 10 Aug 2026 20:55:26 +0800 Subject: [PATCH 21/72] promql: honour @ modifier when evaluating info series (#19266) * promql: honour @ modifier when evaluating info() series --------- Signed-off-by: Jeanette Tan Signed-off-by: Arve Knudsen Co-authored-by: Arve Knudsen --- promql/engine.go | 12 +++-- promql/info.go | 65 ++++++++++++++++++++-------- promql/promqltest/testdata/info.test | 61 ++++++++++++++++++++++++++ 3 files changed, 116 insertions(+), 22 deletions(-) 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/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: From 864715220122a7e2f2ec1f5a81848fbde4c22c35 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Mon, 10 Aug 2026 13:58:00 +0000 Subject: [PATCH 22/72] chore(deps): update modules (#18983) * chore(deps): update modules --------- Signed-off-by: Arve Knudsen Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> Co-authored-by: Arve Knudsen --- web/ui/pnpm-lock.yaml | 296 +++++++++++++++++++++--------------------- 1 file changed, 148 insertions(+), 148 deletions(-) diff --git a/web/ui/pnpm-lock.yaml b/web/ui/pnpm-lock.yaml index 431f970fbf4..c869dc2b83a 100644 --- a/web/ui/pnpm-lock.yaml +++ b/web/ui/pnpm-lock.yaml @@ -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 @@ -115,7 +115,7 @@ importers: 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 @@ -206,7 +206,7 @@ importers: version: 7.0.1(postcss@8.5.23) 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)) @@ -237,7 +237,7 @@ 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(supports-color@8.1.1)) @@ -276,7 +276,7 @@ importers: 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)(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==} @@ -711,12 +711,6 @@ packages: peerDependencies: eslint: ^6.0.0 || ^7.0.0 || >=8.0.0 - '@eslint-community/eslint-utils@4.9.1': - resolution: {integrity: sha512-phrYmNiYppR7znFEdqgfWHXR6NCkZEK7hwWDHZUjit/2/U0r6XvkDl0SYnoM51Hq7FhCGdLDT6zxCCOY1hexsQ==} - engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} - peerDependencies: - eslint: ^6.0.0 || ^7.0.0 || >=8.0.0 - '@eslint-community/regexpp@4.12.2': resolution: {integrity: sha512-EriSTlt5OC9/7SXkRSCAhfSxxoSUgBm33OH+IkwbdpgoqsSsUg7y3uh+IICI/Qg4BBWr3U2i39RpmycbxMq4ew==} engines: {node: ^12.0.0 || ^14.0.0 || >=16.0.0} @@ -986,6 +980,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: @@ -1047,141 +1048,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] @@ -2705,8 +2706,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: @@ -3059,8 +3060,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 @@ -3830,20 +3831,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 @@ -3852,13 +3853,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': @@ -3869,10 +3870,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 @@ -3998,11 +3999,6 @@ snapshots: eslint: 9.39.5(supports-color@8.1.1) eslint-visitor-keys: 3.4.3 - '@eslint-community/eslint-utils@4.9.1(eslint@9.39.5(supports-color@8.1.1))': - dependencies: - 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(supports-color@8.1.1))': @@ -4399,6 +4395,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 @@ -4440,97 +4439,97 @@ snapshots: '@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': {} @@ -4769,7 +4768,7 @@ snapshots: '@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 @@ -4777,16 +4776,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) @@ -5127,7 +5126,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: {} @@ -5360,7 +5359,7 @@ snapshots: eslint@9.39.5(supports-color@8.1.1): dependencies: - '@eslint-community/eslint-utils': 4.9.1(eslint@9.39.5(supports-color@8.1.1)) + '@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(supports-color@8.1.1) '@eslint/config-helpers': 0.4.2 @@ -6250,7 +6249,7 @@ snapshots: 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 @@ -6555,7 +6554,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) @@ -6563,41 +6562,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: {} @@ -6956,7 +6956,7 @@ snapshots: 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 From ff00f15a43bbc1cb2aecafe8787028ba8366b608 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Mon, 10 Aug 2026 16:04:28 +0200 Subject: [PATCH 23/72] chore(deps): update dependency @eslint/compat to v2 (#18885) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- web/ui/mantine-ui/package.json | 2 +- web/ui/module/codemirror-promql/package.json | 2 +- web/ui/pnpm-lock.yaml | 28 +++++++++++++------- 3 files changed, 20 insertions(+), 12 deletions(-) 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/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 c869dc2b83a..73e43fa74ff 100644 --- a/web/ui/pnpm-lock.yaml +++ b/web/ui/pnpm-lock.yaml @@ -157,8 +157,8 @@ importers: 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) devDependencies: '@eslint/compat': - specifier: ^1.4.1 - version: 1.4.1(eslint@9.39.5(supports-color@8.1.1)) + 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(supports-color@8.1.1) @@ -239,8 +239,8 @@ importers: specifier: ^6.43.6 version: 6.43.8 '@eslint/compat': - specifier: ^1.4.1 - version: 1.4.1(eslint@9.39.5(supports-color@8.1.1)) + 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(supports-color@8.1.1) @@ -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} @@ -4001,9 +4005,9 @@ snapshots: '@eslint-community/regexpp@4.12.2': {} - '@eslint/compat@1.4.1(eslint@9.39.5(supports-color@8.1.1))': + '@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(supports-color@8.1.1) @@ -4023,6 +4027,10 @@ snapshots: dependencies: '@types/json-schema': 7.0.15 + '@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 From 706bff80d7a28f6805a661d5fc5af0a7d388c4fe Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Mon, 10 Aug 2026 14:55:29 +0000 Subject: [PATCH 24/72] fix(deps): update dependency react-router-dom to v7 (#19067) * fix(deps): update dependency react-router-dom to v7 * ui: migrate legacy app to React Router v7 --------- Signed-off-by: Arve Knudsen Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> Co-authored-by: Arve Knudsen --- Makefile | 8 +- web/ui/react-app/config-overrides.js | 19 +- web/ui/react-app/package.json | 29 +- web/ui/react-app/pnpm-lock.yaml | 2073 ++++++++--------- web/ui/react-app/pnpm-workspace.yaml | 7 + web/ui/react-app/src/App.test.tsx | 106 +- web/ui/react-app/src/App.tsx | 48 +- web/ui/react-app/src/Navbar.test.tsx | 51 +- web/ui/react-app/src/components/Checkbox.tsx | 3 +- .../src/components/ToggleMoreLess.tsx | 3 +- .../src/hooks/useLocalStorage.test.tsx | 8 +- web/ui/react-app/src/index.tsx | 7 +- .../src/pages/alerts/AlertContents.tsx | 3 +- .../flags/__snapshots__/Flags.test.tsx.snap | 54 +- .../src/pages/graph/HistogramChart.test.tsx | 28 +- .../src/pages/targets/ScrapePoolList.test.tsx | 31 + .../targets/TargetScrapeDuration.test.tsx | 18 + web/ui/react-app/src/setupTests.ts | 8 +- web/ui/react-app/src/utils/utils.test.ts | 2 +- 19 files changed, 1207 insertions(+), 1299 deletions(-) create mode 100644 web/ui/react-app/src/pages/targets/TargetScrapeDuration.test.tsx diff --git a/Makefile b/Makefile index 51f21e6a852..b24d3f0462a 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 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..c28435d7e17 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: .: @@ -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==} @@ -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==} @@ -2652,6 +2650,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 +2711,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 +2833,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 +3389,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 +3431,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 +3479,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 +3759,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 +4177,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 +4192,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 +4502,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 +4537,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 +5141,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 +5181,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 +5215,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 +5315,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 +5438,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 +5495,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 +5881,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 +5919,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 +6008,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 +6081,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 +6185,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 +6230,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 +6342,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 +6368,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 +6416,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 +6449,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 +6478,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 +6509,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 +6526,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 +7246,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 +7254,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,6 +7265,17 @@ 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 @@ -7465,17 +7402,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 +7441,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 +7459,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 +7494,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 +7508,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 +7557,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 +7571,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 +7615,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 +7793,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 +7803,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 +7909,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 +7921,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 +7936,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 +8060,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 +8115,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 +8127,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 +8195,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 +8214,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 +8239,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 +8253,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 +8267,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 +8365,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 +8402,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 +8472,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 +8598,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 +8644,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 +8749,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 +8801,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 +8878,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 +8968,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 +9002,8 @@ snapshots: cookie@0.7.2: {} + cookie@1.1.1: {} + copy-to-clipboard@3.3.3: dependencies: toggle-selection: 1.0.6 @@ -9150,7 +9064,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 +9075,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 +9085,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 +9227,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 +9286,8 @@ snapshots: depd@2.0.0: {} + dequal@2.0.3: {} + destroy@1.2.0: {} detect-libc@2.1.2: @@ -9372,10 +9297,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 +9332,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 +9423,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 +9460,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 +9490,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 +9643,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 +9674,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 +9723,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 +9750,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 +9759,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 +9781,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 +9795,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 +9817,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 +9931,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 +9957,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 +10005,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 +10021,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 +10061,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 +10085,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 +10233,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 +10263,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 +10295,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 +10303,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 +10326,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 +10353,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 +10373,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 +10607,6 @@ snapshots: dependencies: is-docker: 2.2.1 - isarray@0.0.1: {} - isarray@1.0.0: {} isarray@2.0.5: {} @@ -10710,9 +10615,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 +10631,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 +10670,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 +10684,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 +10694,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 +10715,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 +10773,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 +10781,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 +10825,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 +10839,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 +10915,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 +10936,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 +10965,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 +10985,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 +10997,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 +11060,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 +11110,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 +11139,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 +11152,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 +11305,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 +11319,6 @@ snapshots: dependencies: semver: 7.8.5 - make-error@1.3.6: {} - makeerror@1.0.12: dependencies: tmpl: 1.0.5 @@ -11455,11 +11360,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 +11626,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 +11651,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 +11834,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 +12215,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 +12252,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 +12260,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 +12281,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 +12409,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 +12537,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 +12631,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 +12655,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 +12697,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 +12723,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 +12735,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 +12833,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 +12855,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 +12866,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 +12999,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 +13135,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 +13179,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 +13215,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 +13245,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 +13308,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 +13369,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 +13408,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 +13430,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 +13444,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 +13475,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 +13497,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 +13526,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 +13598,6 @@ snapshots: word-wrap@1.2.5: {} - wordwrap@1.0.0: {} - workbox-background-sync@6.6.0: dependencies: idb: 7.1.1 @@ -13764,13 +13607,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 +13706,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 +13754,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` ); }); From bea965eb8769e05b7fbdf0a61a266cdf6569d702 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Mon, 10 Aug 2026 19:24:30 +0200 Subject: [PATCH 25/72] chore(deps): update mantine ui (#18758) * chore(deps): update mantine ui * chore(deps): keep eslint plugin at v0.5.3 Signed-off-by: Arve Knudsen --------- Signed-off-by: Arve Knudsen Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> Co-authored-by: Arve Knudsen --- web/ui/pnpm-lock.yaml | 307 ++++++++++++++++++++++-------------------- 1 file changed, 162 insertions(+), 145 deletions(-) diff --git a/web/ui/pnpm-lock.yaml b/web/ui/pnpm-lock.yaml index 73e43fa74ff..b526b1b1b75 100644 --- a/web/ui/pnpm-lock.yaml +++ b/web/ui/pnpm-lock.yaml @@ -31,7 +31,7 @@ importers: 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: @@ -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,10 +106,10 @@ 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 @@ -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,7 +154,7 @@ 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: ^2.0.0 @@ -167,10 +167,10 @@ importers: 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.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) @@ -179,7 +179,7 @@ importers: 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(supports-color@8.1.1)(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(supports-color@8.1.1) @@ -197,22 +197,22 @@ importers: 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.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(supports-color@8.1.1))(sugarss@5.0.1(postcss@8.5.23))(supports-color@8.1.1) + 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: @@ -762,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' @@ -932,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 @@ -1208,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==} @@ -1292,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==} @@ -2699,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} @@ -2882,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'} @@ -2985,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' @@ -3241,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==} @@ -4063,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': {} @@ -4343,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 @@ -4433,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 @@ -4443,7 +4452,7 @@ 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': {} @@ -4556,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': {} @@ -4591,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: @@ -4655,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 @@ -4875,7 +4884,7 @@ snapshots: '@unrs/resolver-binding-win32-x64-msvc@1.12.2': optional: true - '@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.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(supports-color@8.1.1) '@babel/plugin-transform-react-jsx-self': 7.29.7(@babel/core@7.29.7(supports-color@8.1.1)) @@ -4883,7 +4892,7 @@ snapshots: '@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 @@ -4895,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: @@ -6251,6 +6260,8 @@ snapshots: nanoid@3.3.16: {} + nanoid@3.3.18: {} + napi-postinstall@0.3.4: {} natural-compare@1.4.0: {} @@ -6368,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: @@ -6407,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: @@ -6469,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 @@ -6513,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: @@ -6622,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: @@ -6741,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: @@ -6761,7 +6778,7 @@ snapshots: dependencies: '@pkgr/core': 0.3.6 - tabbable@6.4.0: {} + tabbable@6.5.0: {} tagged-tag@1.0.0: {} @@ -6902,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: @@ -6937,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))(supports-color@8.1.1): + 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(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 @@ -6958,7 +6975,7 @@ 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) @@ -6969,13 +6986,13 @@ snapshots: 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(supports-color@8.1.1))(sugarss@5.0.1(postcss@8.5.23))(supports-color@8.1.1): + 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 @@ -6993,8 +7010,8 @@ 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))(supports-color@8.1.1) + 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 From 5bae6b42459f4c9d9a0027138d5ab862acd2288e Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Mon, 10 Aug 2026 17:35:06 +0000 Subject: [PATCH 26/72] chore(deps): update dependency @codemirror/view to v6.43.8 (#18883) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- web/ui/react-app/pnpm-lock.yaml | 25 +++++++++++++++---------- 1 file changed, 15 insertions(+), 10 deletions(-) diff --git a/web/ui/react-app/pnpm-lock.yaml b/web/ui/react-app/pnpm-lock.yaml index c28435d7e17..e3c37a16287 100644 --- a/web/ui/react-app/pnpm-lock.yaml +++ b/web/ui/react-app/pnpm-lock.yaml @@ -31,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 @@ -971,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==} @@ -2412,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==} @@ -7280,20 +7283,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 @@ -7302,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 @@ -9036,6 +9039,8 @@ snapshots: crelt@1.0.6: {} + crelt@1.0.7: {} + cross-fetch@3.2.0: dependencies: node-fetch: 2.7.0 From d80bc8a6a65c7aae9babb443d3f7d62eb2ec1f78 Mon Sep 17 00:00:00 2001 From: linasm Date: Tue, 11 Aug 2026 13:06:56 +0300 Subject: [PATCH 27/72] Validate histogram in TestFloatHistogramCompact Signed-off-by: linasm --- model/histogram/float_histogram_test.go | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/model/histogram/float_histogram_test.go b/model/histogram/float_histogram_test.go index 73b1496044d..d33f296095a 100644 --- a/model/histogram/float_histogram_test.go +++ b/model/histogram/float_histogram_test.go @@ -1776,9 +1776,13 @@ 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") + } }) } } From 4a75ab11eae348d1833ff1d1942f327c533cfc35 Mon Sep 17 00:00:00 2001 From: Madan Kumar Date: Sun, 2 Aug 2026 07:23:23 +0530 Subject: [PATCH 28/72] histogram: fix Compact corrupting buckets on multiple span merges The final loop of compactBuckets merges spans that are separated by no more than maxEmptyBuckets empty buckets. When it merged a span it advanced iBucket only by the number of empty buckets it inserted, not by the length of the merged span, so every following merge in the same pass spliced its zero fill at a stale position and silently moved real buckets to wrong indices. For integer histograms the same statement also left currentBucketAbsolute at the first bucket of the merged span instead of its last one, which turns the deltas written by the following merge into negative bucket counts. A histogram that passes Validate() before Compact then fails it afterwards, and the bucket iterator reports counts underflowed to huge uint64 values. Advance iBucket past the buckets of the merged span and recompute currentBucketAbsolute from them, the same way the non-merging branch does. The bug needs at least two merges in one pass, which is why the existing "everything merged into one span" cases did not catch it. Signed-off-by: Madan Kumar --- model/histogram/float_histogram_test.go | 36 +++++++++++++++++++++++++ model/histogram/generic.go | 14 +++++++++- model/histogram/histogram_test.go | 22 +++++++++++++++ 3 files changed, 71 insertions(+), 1 deletion(-) diff --git a/model/histogram/float_histogram_test.go b/model/histogram/float_histogram_test.go index d33f296095a..3c471794b39 100644 --- a/model/histogram/float_histogram_test.go +++ b/model/histogram/float_histogram_test.go @@ -1676,6 +1676,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{ @@ -1787,6 +1803,26 @@ func TestFloatHistogramCompact(t *testing.T) { } } +// 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") + } }) } } From 1cf570b12ed1ff51da30574f664716882d5277c4 Mon Sep 17 00:00:00 2001 From: Vishnu Kothakapu Date: Mon, 10 Aug 2026 01:39:37 +0530 Subject: [PATCH 29/72] docs: add native histogram examples to OpenAPI spec Signed-off-by: Vishnu Kothakapu --- web/api/v1/openapi_examples.go | 46 ++++++++++++++++++++++++++++++++-- 1 file changed, 44 insertions(+), 2 deletions(-) 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 } From 5c5f0228b2ab0bbf554738428c11d15326653f68 Mon Sep 17 00:00:00 2001 From: Vishnu Kothakapu Date: Mon, 10 Aug 2026 01:54:07 +0530 Subject: [PATCH 30/72] test: update OpenAPI golden test files Signed-off-by: Vishnu Kothakapu --- web/api/v1/testdata/openapi_3.1_golden.yaml | 12 ++++++++++++ web/api/v1/testdata/openapi_3.2_golden.yaml | 12 ++++++++++++ 2 files changed, 24 insertions(+) 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: From 36ec34c5378ce369cc37a77977e1952ae1e911e9 Mon Sep 17 00:00:00 2001 From: Sueun Cho Date: Sat, 8 Aug 2026 17:49:23 +0900 Subject: [PATCH 31/72] fix(model/histogram): do not miss counter resets behind empty buckets in DetectReset The two inner loops in the detectReset helper advance prevIt with prevIt.Next() but never reassign prevBucket = prevIt.strippedAt(), so they keep inspecting the first previous bucket. When that bucket is empty and a later one is populated and missing from the current histogram, DetectReset returns false and misses a real counter reset, which can make native-histogram rate()/increase() undercount. Added two cases to TestFloatHistogramDetectReset that fail before and pass after. Signed-off-by: Sueun Cho --- model/histogram/float_histogram.go | 2 ++ model/histogram/float_histogram_test.go | 41 +++++++++++++++++++++++++ 2 files changed, 43 insertions(+) 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 3c471794b39..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 { From 89f8d5a046ab5fa8e9ed588c07d8aa5ada83defe Mon Sep 17 00:00:00 2001 From: Daile Alimo Date: Wed, 5 Aug 2026 21:15:41 +0100 Subject: [PATCH 32/72] OS agnostic tests Signed-off-by: Daile Alimo --- cmd/prometheus/main_test.go | 19 +++++++++++-------- 1 file changed, 11 insertions(+), 8 deletions(-) diff --git a/cmd/prometheus/main_test.go b/cmd/prometheus/main_test.go index 29cb0713528..7531aaa6c42 100644 --- a/cmd/prometheus/main_test.go +++ b/cmd/prometheus/main_test.go @@ -704,9 +704,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 +716,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) { @@ -1216,9 +1218,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 +1229,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) { From bb17c0f849e409bdf3c8fda62d0edcee1f88631f Mon Sep 17 00:00:00 2001 From: Daile Alimo Date: Sat, 8 Aug 2026 12:05:27 +0100 Subject: [PATCH 33/72] config: A missing OTLPConfig to windows expected config - fixes failing test on windows Signed-off-by: Daile Alimo --- config/config_windows_test.go | 1 + 1 file changed, 1 insertion(+) 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", From 83390dd5e5dc1388bf53b4876abb4ddd56ed7c90 Mon Sep 17 00:00:00 2001 From: Daile Alimo Date: Sat, 8 Aug 2026 13:22:02 +0100 Subject: [PATCH 34/72] add missing filepath.FromSlash where required - fix windows tests Signed-off-by: Daile Alimo --- config/config_test.go | 37 +++++++++++++++++++++---------------- 1 file changed, 21 insertions(+), 16 deletions(-) diff --git a/config/config_test.go b/config/config_test.go index b18972c00fa..f98e0acab00 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"), @@ -229,7 +230,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 +264,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 +1115,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 +1271,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 +1314,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 +1358,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 +1842,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, }, }, From ab14ea740a9dc3dc1b94d6cb4bedb0f66702aa6b Mon Sep 17 00:00:00 2001 From: Julien Pivotto <291750+roidelapluie@users.noreply.github.com> Date: Tue, 11 Aug 2026 15:35:20 +0200 Subject: [PATCH 35/72] build: fix shell syntax error in update-go-deps targets The comment sat in the middle of a backslash-continued recipe, so the for-loop reached the shell unterminated: >> updating Go dependencies sh: -c: line 3: syntax error: unexpected end of file from `for' command on line 1 make: *** [Makefile.common:168: update-go-deps] Error 2 make update-go-deps, update-go-deps-in-dir and update-all-go-deps always failed this way. Move the comment out of the recipe's shell text. Makefile.common here is the canonical copy synced by scripts/sync_repo_files.sh, so the other repos get the fix on next sync. Signed-off-by: Julien Pivotto <291750+roidelapluie@users.noreply.github.com> --- Makefile | 2 +- Makefile.common | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Makefile b/Makefile index b24d3f0462a..fb92ce87bc1 100644 --- a/Makefile +++ b/Makefile @@ -226,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 From 4cbd42c91cee5d60a6a1ec63aff0252b1094c558 Mon Sep 17 00:00:00 2001 From: Perfloop Agent Date: Wed, 12 Aug 2026 14:11:10 +0200 Subject: [PATCH 36/72] perf(remote): pool OTLP converter scratch state (#19388) * remote: add OTLP write handler benchmark * remote: pool OTLP converter scratch state --------- Signed-off-by: Perfloop Agent --- .../prometheusremotewrite/metrics_to_prw.go | 37 ++++++- .../metrics_to_prw_test.go | 92 ++++++++++++++++ storage/remote/write_otlp_handler.go | 16 ++- storage/remote/write_otlp_handler_test.go | 102 ++++++++++++++++++ 4 files changed, 240 insertions(+), 7 deletions(-) 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) From aaaea0fb82b2dd95b17dc7ccc16991691e5d320a Mon Sep 17 00:00:00 2001 From: Periklis Tsirakidis Date: Mon, 13 Jul 2026 13:28:18 +0200 Subject: [PATCH 37/72] fix: address OOO chunk ID overflow [WIP] Signed-off-by: Periklis Tsirakidis --- tsdb/db_test.go | 65 +++++++++++ tsdb/head.go | 2 +- tsdb/head_read.go | 17 ++- tsdb/head_test.go | 231 +++++++++++++++++++++++++++++++++++++ tsdb/ooo_head_read_test.go | 148 ++++++++++++++++++++++++ 5 files changed, 457 insertions(+), 6 deletions(-) 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..34f1b970ad3 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) << 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..c5a3d3119bf 100644 --- a/tsdb/head_test.go +++ b/tsdb/head_test.go @@ -1862,6 +1862,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} { @@ -10436,3 +10514,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 + } +} From 263201d9b9290763f4afa16136e10572c9fb040d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gy=C3=B6rgy=20Krajcsovits?= Date: Thu, 6 Aug 2026 09:55:53 +0200 Subject: [PATCH 38/72] cmd/prometheus: fix flaky TestRuntimeGOGCConfig MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit TestRuntimeGOGCConfig gave the spawned Prometheus 5 seconds to serve /metrics, the shortest deadline in the package. CI runs these tests with the race detector, so both the test binary and the Prometheus processes it spawns in parallel are instrumented, and 5 seconds is not always enough to get as far as creating the web listener: --- FAIL: TestRuntimeGOGCConfig/empty_config_file_with_GOGC_env_var_set (5.07s) main_test.go:918: Condition never satisfied Replace the four copies of the readiness wait spread over the package with a single waitForPrometheusReady helper and give it a more generous deadline. Waiting on /-/ready instead of /metrics also removes a second race: /metrics is served before the initial configuration is applied, so the GOGC gauge could still hold the default when it was first scraped. While here, drop an inherited GOGC from the environment of the spawned Prometheus. Without that, running the test with GOGC set in the environment fails the cases that expect the default or the configured value. Signed-off-by: György Krajcsovits --- cmd/prometheus/features_test.go | 11 +---------- cmd/prometheus/main_test.go | 35 ++++++++++++--------------------- cmd/prometheus/reload_test.go | 31 +++++++++++++++++++++-------- 3 files changed, 37 insertions(+), 40 deletions(-) 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_test.go b/cmd/prometheus/main_test.go index 7531aaa6c42..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) } @@ -904,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. 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") +} From 09028a21269c5a24c4209315aac2543d4cf2d2c0 Mon Sep 17 00:00:00 2001 From: Daile Alimo Date: Wed, 5 Aug 2026 18:02:19 +0100 Subject: [PATCH 39/72] make panic lock-release test OS agnostic - remove windows guard Signed-off-by: Daile Alimo --- tsdb/head_test.go | 28 +++++++++++++++++----------- 1 file changed, 17 insertions(+), 11 deletions(-) diff --git a/tsdb/head_test.go b/tsdb/head_test.go index c5a3d3119bf..60a3c7bdf52 100644 --- a/tsdb/head_test.go +++ b/tsdb/head_test.go @@ -24,7 +24,6 @@ import ( "path" "path/filepath" "reflect" - "runtime" "slices" "sort" "strconv" @@ -10085,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)) @@ -10108,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)) + h.chunkDiskMapper.CutNewFile() // 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 @@ -10121,9 +10119,17 @@ func TestHead_mmapHeadChunks(t *testing.T) { require.Panics(t, func() { h.mmapHeadChunks() }) + // Probe the locks without blocking. On failure the leaked locks are + // released, so that the test fails instead of hanging forever in the + // deferred Head.Close. + seriesFree := s.TryLock() + if seriesFree { + s.Unlock() + } + // The locks held while mmapChunks panicked must have been released. - require.True(t, s.TryLock(), "series lock leaked after panic") - s.Unlock() + require.True(t, seriesFree, "series lock still held after panic, any later m-mapping would block forever") + for i := range h.series.size { require.Truef(t, h.series.locks[i].TryLock(), "stripe lock %d leaked after panic", i) h.series.locks[i].Unlock() From 8409d6135227f0c3ecd5555cb77ce4dc1422ae38 Mon Sep 17 00:00:00 2001 From: Daile Alimo Date: Fri, 7 Aug 2026 21:29:32 +0100 Subject: [PATCH 40/72] tsdb/head_test.go revert unrelated changes Signed-off-by: Daile Alimo --- tsdb/head_test.go | 12 ++---------- 1 file changed, 2 insertions(+), 10 deletions(-) diff --git a/tsdb/head_test.go b/tsdb/head_test.go index 60a3c7bdf52..b6107fb6c0e 100644 --- a/tsdb/head_test.go +++ b/tsdb/head_test.go @@ -10119,17 +10119,9 @@ func TestHead_mmapHeadChunks(t *testing.T) { require.Panics(t, func() { h.mmapHeadChunks() }) - // Probe the locks without blocking. On failure the leaked locks are - // released, so that the test fails instead of hanging forever in the - // deferred Head.Close. - seriesFree := s.TryLock() - if seriesFree { - s.Unlock() - } - // The locks held while mmapChunks panicked must have been released. - require.True(t, seriesFree, "series lock still held after panic, any later m-mapping would block forever") - + require.True(t, s.TryLock(), "series lock leaked after panic") + s.Unlock() for i := range h.series.size { require.Truef(t, h.series.locks[i].TryLock(), "stripe lock %d leaked after panic", i) h.series.locks[i].Unlock() From ff143ff9d0ebfdb7b6bc897a347e7d0b021909fe Mon Sep 17 00:00:00 2001 From: Daile Alimo Date: Wed, 12 Aug 2026 23:39:01 +0100 Subject: [PATCH 41/72] remove superfluous call to CutNewFile Signed-off-by: Daile Alimo --- tsdb/head_test.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tsdb/head_test.go b/tsdb/head_test.go index b6107fb6c0e..7f0fa1a1e06 100644 --- a/tsdb/head_test.go +++ b/tsdb/head_test.go @@ -10109,7 +10109,7 @@ func TestHead_mmapHeadChunks(t *testing.T) { // 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)) - h.chunkDiskMapper.CutNewFile() + // 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 From 4b0276794ca26d26a4fa0cc204efc3f0afdf799f Mon Sep 17 00:00:00 2001 From: Rohit Behera <126186063+r0h1tb@users.noreply.github.com> Date: Mon, 3 Aug 2026 22:46:41 +0530 Subject: [PATCH 42/72] discovery/aws: don't panic on ECS tasks with absent optional fields ECS SD dereferenced eight optional pointer fields while building each task's label set, plus two more in the ENI attachment loop, without a nil check: switch *detail.Name { // ecs.go:879 ipAddress = *detail.Value ecsLabelClusterARN: model.LabelValue(*cluster.ClusterArn), ecsLabelTaskGroup: model.LabelValue(*task.Group), ecsLabelAvailabilityZone: model.LabelValue(*task.AvailabilityZone), ... None of these carry "This member is required" in the AWS SDK, unlike 120 other fields in the same types.go, so every one of them can legitimately be absent. 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. getServiceNameFromTaskGroup had a related failure. isStandaloneTask returns false when Group is nil, so a task with no Group took the service branch and then dereferenced *task.Group; strings.Split(...)[1] also panicked with an index error for a group that carries no colon. It now returns an empty name for both. Because the panic happens on the discovery refresh goroutine it takes down the whole Prometheus process rather than degrading the single target. Each label is now emitted only when its source field is present, matching the guarding already used a few lines below for ContainerInstanceArn, PlatformFamily and the tag pairs. The three debug log statements use aws.ToString for the task ARN, the idiom already used throughout msk.go. Adds a TaskWithNilOptionalFields case to the existing TestECSDiscoveryRefresh table. The test harness also now sets the no-op logger that NewECSDiscovery substitutes in production, without which the debug paths panic on a nil logger. Signed-off-by: Rohit Behera <126186063+r0h1tb@users.noreply.github.com> --- discovery/aws/ecs.go | 61 ++++++++++++++++++++++++++---------- discovery/aws/ecs_test.go | 66 +++++++++++++++++++++++++++++++++++++++ 2 files changed, 110 insertions(+), 17 deletions(-) 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) From 00beada4b991e94f1aef7303562477bc682a872d Mon Sep 17 00:00:00 2001 From: aamoghS Date: Wed, 12 Aug 2026 23:04:57 -0400 Subject: [PATCH 43/72] promql/parser: reject offset expressions and @ start()/end() before range selectors The matrix_selector rule only inspected OriginalOffset and Timestamp, so foo offset step()[5m] and foo @ start()[5m] were accepted while the equivalent literal forms were rejected. Signed-off-by: aamoghS Co-authored-by: Cursor --- promql/parser/generated_parser.y | 4 ++-- promql/parser/generated_parser.y.go | 4 ++-- promql/parser/parse_test.go | 33 +++++++++++++++++++++++++++++ 3 files changed, 37 insertions(+), 4 deletions(-) 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, From 060fbe2f62168f7465562ee00659b2afae448709 Mon Sep 17 00:00:00 2001 From: aamoghS Date: Wed, 12 Aug 2026 23:08:26 -0400 Subject: [PATCH 44/72] docs: note that Kubernetes pod __address__ may omit the port Relabel docs stated __address__ is always host:port, but pod SD leaves the port off when a container declares none so it can be added via relabeling. Signed-off-by: aamoghS Co-authored-by: Cursor --- docs/configuration/configuration.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/docs/configuration/configuration.md b/docs/configuration/configuration.md index 93fc74a68c9..3d8e2a9f9b5 100644 --- a/docs/configuration/configuration.md +++ b/docs/configuration/configuration.md @@ -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. From d551c8a5b6c6195c36942b075a24291f643ec13d Mon Sep 17 00:00:00 2001 From: Julien <291750+roidelapluie@users.noreply.github.com> Date: Thu, 13 Aug 2026 14:04:39 +0200 Subject: [PATCH 45/72] tsdb: document that OOO chunk IDs are no longer monotonically increasing (#19401) * tsdb: document that OOO chunk IDs are no longer monotonically increasing Follow-up to #19216: the HeadChunkID doc still promised a monotonically increasing per-series number, which no longer holds for out-of-order chunk IDs now that they wrap modulo 2^23. Also spell out the "much less than" relation in the oooHeadChunkID comment, where << is easy to misread as a bit-shift. Signed-off-by: Julien Pivotto <291750+roidelapluie@users.noreply.github.com> * Update tsdb/head_read.go Co-authored-by: George Krajcsovits Signed-off-by: Julien <291750+roidelapluie@users.noreply.github.com> --------- Signed-off-by: Julien Pivotto <291750+roidelapluie@users.noreply.github.com> Signed-off-by: Julien <291750+roidelapluie@users.noreply.github.com> Co-authored-by: George Krajcsovits --- tsdb/chunks/chunks.go | 5 ++++- tsdb/head_read.go | 4 ++-- 2 files changed, 6 insertions(+), 3 deletions(-) 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/head_read.go b/tsdb/head_read.go index 34f1b970ad3..20cdf6ee156 100644 --- a/tsdb/head_read.go +++ b/tsdb/head_read.go @@ -420,8 +420,8 @@ const oooChunkIDMask = 1 << 23 // // The position is wrapped modulo oooChunkIDMask so that firstOOOChunkID can // grow indefinitely without overflowing the 23-bit ID space. Correctness -// requires len(oooMmappedChunks) << oooChunkIDMask, which is enforced by the -// guard in mmapCurrentOOOHeadChunk. +// 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 - 1)) | oooChunkIDMask } From f5285529ecff2d73755473c8e04eeae06288a2ed Mon Sep 17 00:00:00 2001 From: David Ashpole Date: Fri, 7 Aug 2026 17:14:02 +0000 Subject: [PATCH 46/72] Implement memory limiter prototype --- cmd/prometheus/main.go | 43 ++- config/config.go | 104 +++++- rules/group.go | 7 + rules/manager.go | 4 + scrape/manager.go | 5 +- scrape/metrics.go | 9 + scrape/scrape.go | 22 +- scrape/scrape_test.go | 87 +++++ util/memorylimiter/memory_limiter.go | 389 ++++++++++++++++++++++ util/memorylimiter/memory_limiter_test.go | 153 +++++++++ util/memorylimiter/metrics.go | 81 +++++ web/api/v1/api.go | 23 ++ web/federate.go | 6 + web/web.go | 7 + 14 files changed, 922 insertions(+), 18 deletions(-) create mode 100644 util/memorylimiter/memory_limiter.go create mode 100644 util/memorylimiter/memory_limiter_test.go create mode 100644 util/memorylimiter/metrics.go diff --git a/cmd/prometheus/main.go b/cmd/prometheus/main.go index 6e6c61d0f35..a3b4d25ccc9 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,20 @@ func main() { }, ) } + if memoryLimiter != nil { + ctxML, cancelML := context.WithCancel(context.Background()) + g.Add( + func() error { + memoryLimiter.Start(ctxML) + return nil + }, + func(error) { + logger.Info("Stopping memory limiter...") + cancelML() + memoryLimiter.Stop() + }, + ) + } if !agentMode { // Rule manager. g.Add( diff --git a/config/config.go b/config/config.go index 7777a02ba8d..5cd0e7426ab 100644 --- a/config/config.go +++ b/config/config.go @@ -196,6 +196,23 @@ var ( GoGC: getGoGC(), } + DefaultMemoryLimiterConfig = MemoryLimiterConfig{ + CheckInterval: model.Duration(100 * time.Millisecond), + SoftLimitRatio: 0.70, + HardLimitRatio: 0.85, + Enforcement: DefaultMemoryLimiterEnforcement, + } + + DefaultMemoryLimiterEnforcement = MemoryLimiterEnforcement{ + PauseBlockCompaction: true, + RejectRemoteRead: true, + RejectFederation: true, + FailScrapes: true, + RejectOTLP: true, + RejectRemoteWrite: true, + PauseRecordingRules: true, + } + // DefaultScrapeConfig is the default scrape configuration. Users of this // default MUST call Validate() on the config after creation, even if it's // used unaltered, to check for parameter correctness and fill out default @@ -735,25 +752,82 @@ 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 + PauseBlockCompaction bool `yaml:"pause_block_compaction,omitempty"` + 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.PauseBlockCompaction && !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.isZero() { + return nil + } + 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 (exclusive), 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 (exclusive), 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/rules/group.go b/rules/group.go index 704fd13d850..c805c439e84 100644 --- a/rules/group.go +++ b/rules/group.go @@ -528,6 +528,13 @@ func (g *Group) Eval(ctx context.Context, ts time.Time) { logger = logger.With("trace_id", sp.SpanContext().TraceID()) } + if _, isAlert := rule.(*AlertingRule); !isAlert { + if g.opts.MemoryLimiter != nil && !g.opts.MemoryLimiter.AllowRecordingRules() { + g.metrics.IterationsMissed.WithLabelValues(GroupKey(g.File(), g.Name())).Inc() + return + } + } + g.metrics.EvalTotal.WithLabelValues(GroupKey(g.File(), g.Name())).Inc() vector, err := rule.Eval(ctx, ruleQueryOffset, ts, g.opts.QueryFunc, g.opts.ExternalURL, g.Limit()) 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/scrape/manager.go b/scrape/manager.go index 55a4e11cdd3..f9d9fec3d7e 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" ) @@ -175,9 +176,11 @@ type Options struct { // initialized immediately upon startup. It also prevents capturing // intermediate state (such as applications crashing shortly after booting), // and ensures backend rate limits don't drop valuable shutdown scrapes - // 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..f0e6909b010 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_skipped_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 { 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..df36c37ace9 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,89 @@ 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) AllowBlockCompaction() bool { return m.allowScrape } +func (m *mockMemoryLimiter) AllowRecordingRules() bool { return m.allowScrape } +func (m *mockMemoryLimiter) ApplyConfig(*config.MemoryLimiterConfig) error { return nil } +func (m *mockMemoryLimiter) Start(context.Context) {} +func (m *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/util/memorylimiter/memory_limiter.go b/util/memorylimiter/memory_limiter.go new file mode 100644 index 00000000000..c3f3fdde463 --- /dev/null +++ b/util/memorylimiter/memory_limiter.go @@ -0,0 +1,389 @@ +// 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" + "sync/atomic" + "time" + + "github.com/prometheus/client_golang/prometheus" + "github.com/prometheus/prometheus/config" +) + +type LimiterState int32 + +const ( + StateOK LimiterState = iota + StateSoftLimit + StateHardLimit +) + +func (s LimiterState) String() string { + switch s { + case StateOK: + return "ok" + case StateSoftLimit: + return "soft" + case StateHardLimit: + return "hard" + default: + return "unknown" + } +} + +type MemoryLimiter interface { + State() LimiterState + AllowScrape() bool + AllowOTLP() bool + AllowRemoteWrite() bool + AllowRemoteRead() bool + AllowFederation() bool + AllowBlockCompaction() bool + AllowRecordingRules() bool + ApplyConfig(cfg *config.MemoryLimiterConfig) error + Start(ctx context.Context) + Stop() +} + +type MemoryStats struct { + TotalBytes uint64 + ReleasedBytes uint64 + GOMEMLIMIT uint64 + GCLimiterCycle uint64 +} + +type MetricsReader func() MemoryStats + +func defaultMetricsReader() MemoryStats { + samples := []metrics.Sample{ + {Name: "/memory/classes/total:bytes"}, + {Name: "/memory/classes/heap/released:bytes"}, + {Name: "/gc/gomemlimit:bytes"}, + {Name: "/gc/limiter/last-enabled:gc-cycle"}, + } + metrics.Read(samples) + var stats MemoryStats + if samples[0].Value.Kind() == metrics.KindUint64 { + stats.TotalBytes = samples[0].Value.Uint64() + } + if samples[1].Value.Kind() == metrics.KindUint64 { + stats.ReleasedBytes = samples[1].Value.Uint64() + } + if samples[2].Value.Kind() == metrics.KindUint64 { + stats.GOMEMLIMIT = samples[2].Value.Uint64() + } + if samples[3].Value.Kind() == metrics.KindUint64 { + stats.GCLimiterCycle = samples[3].Value.Uint64() + } + return stats +} + +type Manager struct { + logger *slog.Logger + + mu sync.RWMutex + config *config.MemoryLimiterConfig + + state atomic.Int32 + lastInUse atomic.Uint64 + lastGCLimiterCycle uint64 + lastCheckTime time.Time + + metricsReader MetricsReader + now func() time.Time + + metrics *memoryLimiterMetrics + + cancel context.CancelFunc + wg sync.WaitGroup +} + +func NewManager(cfg *config.MemoryLimiterConfig, logger *slog.Logger, reg prometheus.Registerer) (*Manager, error) { + if logger == nil { + logger = slog.Default() + } + + m := &Manager{ + logger: logger.With("component", "memory limiter"), + config: cfg, + metricsReader: defaultMetricsReader, + now: time.Now, + metrics: newMemoryLimiterMetrics(reg), + } + + if cfg != nil { + if err := cfg.Validate(); err != nil { + return nil, fmt.Errorf("invalid memory limiter config: %w", err) + } + } + + return m, nil +} + +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 + return nil +} + +func (m *Manager) State() LimiterState { + if m == nil { + return StateOK + } + return LimiterState(m.state.Load()) +} + +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.mu.Unlock() + + m.wg.Add(1) + go m.run(loopCtx) +} + +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 <-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() + + if m.config == nil { + m.state.Store(int32(StateOK)) + return + } + + stats := m.metricsReader() + totalBytes := stats.TotalBytes + releasedBytes := stats.ReleasedBytes + gomemlimit := stats.GOMEMLIMIT + gcLimiterCycle := stats.GCLimiterCycle + + if gomemlimit == 0 || gomemlimit == math.MaxInt64 { + // GOMEMLIMIT not configured or unlimited. + m.state.Store(int32(StateOK)) + return + } + + var inUse uint64 + if totalBytes > releasedBytes { + inUse = totalBytes - 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 { + if oldState == StateSoftLimit { + m.metrics.engagedSecondsTotal.WithLabelValues("soft").Add(elapsed) + } else if oldState == StateHardLimit { + m.metrics.engagedSecondsTotal.WithLabelValues("hard").Add(elapsed) + } + } + + pressureRatio := float64(inUse) / float64(gomemlimit) + + gcLimiterActive := gcLimiterCycle > m.lastGCLimiterCycle && m.lastGCLimiterCycle != 0 + m.lastGCLimiterCycle = gcLimiterCycle + + var newState LimiterState + if pressureRatio >= m.config.HardLimitRatio || gcLimiterActive { + newState = StateHardLimit + } else if pressureRatio >= m.config.SoftLimitRatio { + newState = StateSoftLimit + } else { + 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. + if newState == StateHardLimit { + m.metrics.active.WithLabelValues("hard").Set(1) + m.metrics.active.WithLabelValues("soft").Set(1) + } else if newState == StateSoftLimit { + m.metrics.active.WithLabelValues("hard").Set(0) + m.metrics.active.WithLabelValues("soft").Set(1) + } else { + 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)) +} + +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 +} + +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 +} + +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 +} + +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 +} + +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 +} + +func (m *Manager) AllowBlockCompaction() bool { + if m == nil { + return true + } + m.mu.RLock() + cfg := m.config + m.mu.RUnlock() + if cfg == nil || !cfg.Enforcement.PauseBlockCompaction { + return true + } + return LimiterState(m.state.Load()) < StateSoftLimit +} + +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..9311aba9cc0 --- /dev/null +++ b/util/memorylimiter/memory_limiter_test.go @@ -0,0 +1,153 @@ +// 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{ + PauseBlockCompaction: true, + 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.AllowBlockCompaction()) + 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.False(t, mgr.AllowBlockCompaction()) + 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.AllowBlockCompaction()) + 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()) + require.True(t, mgr.AllowBlockCompaction()) +} + +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/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/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). From bb31d710c5f2277579b47986e283535ebff8cfb6 Mon Sep 17 00:00:00 2001 From: David Ashpole Date: Fri, 7 Aug 2026 18:20:31 +0000 Subject: [PATCH 47/72] Add unit test for memory limiter recording rule skipping --- rules/manager_test.go | 73 +++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 73 insertions(+) diff --git a/rules/manager_test.go b/rules/manager_test.go index 2e3ccf781c6..1927f52a6ad 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,74 @@ 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 (m *mockRuleMemoryLimiter) State() memorylimiter.LimiterState { + return memorylimiter.StateHardLimit +} +func (m *mockRuleMemoryLimiter) AllowScrape() bool { return true } +func (m *mockRuleMemoryLimiter) AllowOTLP() bool { return true } +func (m *mockRuleMemoryLimiter) AllowRemoteWrite() bool { return true } +func (m *mockRuleMemoryLimiter) AllowRemoteRead() bool { return true } +func (m *mockRuleMemoryLimiter) AllowFederation() bool { return true } +func (m *mockRuleMemoryLimiter) AllowBlockCompaction() bool { return true } +func (m *mockRuleMemoryLimiter) AllowRecordingRules() bool { return m.allowRecordingRules } +func (m *mockRuleMemoryLimiter) ApplyConfig(*config.MemoryLimiterConfig) error { return nil } +func (m *mockRuleMemoryLimiter) Start(context.Context) {} +func (m *mockRuleMemoryLimiter) Stop() {} + +func TestGroup_MemoryLimiterRecordingRuleSkipping(t *testing.T) { + storage := teststorage.New(t) + defer storage.Close() + + var alertFired atomic.Bool + notifyFunc := func(ctx context.Context, expr string, alerts ...*Alert) { + alertFired.Store(true) + } + + queryFunc := func(ctx context.Context, q 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 (IterationsMissed incremented, no sample persisted). + require.Equal(t, float64(1), testutil.ToFloat64(opts.Metrics.IterationsMissed.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") +} From 5078a0b501d22289103918e357e8accfa8313c17 Mon Sep 17 00:00:00 2001 From: David Ashpole Date: Fri, 7 Aug 2026 18:28:34 +0000 Subject: [PATCH 48/72] Fix scrape unregister metric leak and memory limiter edge cases --- scrape/metrics.go | 1 + util/memorylimiter/memory_limiter.go | 51 ++++++++++++++++++++-------- 2 files changed, 37 insertions(+), 15 deletions(-) diff --git a/scrape/metrics.go b/scrape/metrics.go index f0e6909b010..0418213e01b 100644 --- a/scrape/metrics.go +++ b/scrape/metrics.go @@ -345,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/util/memorylimiter/memory_limiter.go b/util/memorylimiter/memory_limiter.go index c3f3fdde463..e81575fcd75 100644 --- a/util/memorylimiter/memory_limiter.go +++ b/util/memorylimiter/memory_limiter.go @@ -101,18 +101,20 @@ type Manager struct { mu sync.RWMutex config *config.MemoryLimiterConfig - state atomic.Int32 - lastInUse atomic.Uint64 - lastGCLimiterCycle uint64 - lastCheckTime time.Time + state atomic.Int32 + lastInUse atomic.Uint64 + lastGCLimiterCycle uint64 + gcLimiterInitialized bool + lastCheckTime time.Time metricsReader MetricsReader now func() time.Time metrics *memoryLimiterMetrics - cancel context.CancelFunc - wg sync.WaitGroup + reloadCh chan struct{} + cancel context.CancelFunc + wg sync.WaitGroup } func NewManager(cfg *config.MemoryLimiterConfig, logger *slog.Logger, reg prometheus.Registerer) (*Manager, error) { @@ -126,6 +128,7 @@ func NewManager(cfg *config.MemoryLimiterConfig, logger *slog.Logger, reg promet metricsReader: defaultMetricsReader, now: time.Now, metrics: newMemoryLimiterMetrics(reg), + reloadCh: make(chan struct{}, 1), } if cfg != nil { @@ -148,6 +151,12 @@ func (m *Manager) ApplyConfig(cfg *config.MemoryLimiterConfig) error { } m.config = cfg + + select { + case m.reloadCh <- struct{}{}: + default: + } + return nil } @@ -203,6 +212,15 @@ func (m *Manager) run(ctx context.Context) { 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() } @@ -214,20 +232,22 @@ func (m *Manager) Evaluate() { m.mu.Lock() defer m.mu.Unlock() - if m.config == nil { - m.state.Store(int32(StateOK)) - return - } - stats := m.metricsReader() totalBytes := stats.TotalBytes releasedBytes := stats.ReleasedBytes gomemlimit := stats.GOMEMLIMIT gcLimiterCycle := stats.GCLimiterCycle - if gomemlimit == 0 || gomemlimit == math.MaxInt64 { - // GOMEMLIMIT not configured or unlimited. - m.state.Store(int32(StateOK)) + if m.config == nil || gomemlimit == 0 || gomemlimit == math.MaxInt64 { + 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 } @@ -255,8 +275,9 @@ func (m *Manager) Evaluate() { pressureRatio := float64(inUse) / float64(gomemlimit) - gcLimiterActive := gcLimiterCycle > m.lastGCLimiterCycle && m.lastGCLimiterCycle != 0 + gcLimiterActive := m.gcLimiterInitialized && gcLimiterCycle > m.lastGCLimiterCycle m.lastGCLimiterCycle = gcLimiterCycle + m.gcLimiterInitialized = true var newState LimiterState if pressureRatio >= m.config.HardLimitRatio || gcLimiterActive { From f1c587143d4a0f58ad6783f80d570eef7a843e5b Mon Sep 17 00:00:00 2001 From: David Ashpole Date: Fri, 7 Aug 2026 18:49:17 +0000 Subject: [PATCH 49/72] memory_limiter: fix actor lifecycle termination and heap free bytes accounting --- cmd/prometheus/main.go | 1 + util/memorylimiter/memory_limiter.go | 16 +++++++++++----- 2 files changed, 12 insertions(+), 5 deletions(-) diff --git a/cmd/prometheus/main.go b/cmd/prometheus/main.go index a3b4d25ccc9..4ad2ede8628 100644 --- a/cmd/prometheus/main.go +++ b/cmd/prometheus/main.go @@ -1326,6 +1326,7 @@ func main() { g.Add( func() error { memoryLimiter.Start(ctxML) + <-ctxML.Done() return nil }, func(error) { diff --git a/util/memorylimiter/memory_limiter.go b/util/memorylimiter/memory_limiter.go index e81575fcd75..e8549673d9e 100644 --- a/util/memorylimiter/memory_limiter.go +++ b/util/memorylimiter/memory_limiter.go @@ -64,6 +64,7 @@ type MemoryLimiter interface { type MemoryStats struct { TotalBytes uint64 + FreeBytes uint64 ReleasedBytes uint64 GOMEMLIMIT uint64 GCLimiterCycle uint64 @@ -74,6 +75,7 @@ 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"}, @@ -84,13 +86,16 @@ func defaultMetricsReader() MemoryStats { stats.TotalBytes = samples[0].Value.Uint64() } if samples[1].Value.Kind() == metrics.KindUint64 { - stats.ReleasedBytes = samples[1].Value.Uint64() + stats.FreeBytes = samples[1].Value.Uint64() } if samples[2].Value.Kind() == metrics.KindUint64 { - stats.GOMEMLIMIT = samples[2].Value.Uint64() + stats.ReleasedBytes = samples[2].Value.Uint64() } if samples[3].Value.Kind() == metrics.KindUint64 { - stats.GCLimiterCycle = samples[3].Value.Uint64() + stats.GOMEMLIMIT = samples[3].Value.Uint64() + } + if samples[4].Value.Kind() == metrics.KindUint64 { + stats.GCLimiterCycle = samples[4].Value.Uint64() } return stats } @@ -234,6 +239,7 @@ func (m *Manager) Evaluate() { stats := m.metricsReader() totalBytes := stats.TotalBytes + freeBytes := stats.FreeBytes releasedBytes := stats.ReleasedBytes gomemlimit := stats.GOMEMLIMIT gcLimiterCycle := stats.GCLimiterCycle @@ -252,8 +258,8 @@ func (m *Manager) Evaluate() { } var inUse uint64 - if totalBytes > releasedBytes { - inUse = totalBytes - releasedBytes + if totalBytes > (freeBytes + releasedBytes) { + inUse = totalBytes - (freeBytes + releasedBytes) } m.lastInUse.Store(inUse) From ec019c560f8946c7d36cc1741fd3f37cb0789487 Mon Sep 17 00:00:00 2001 From: David Ashpole Date: Sat, 8 Aug 2026 02:13:21 +0000 Subject: [PATCH 50/72] Introduce distinct metric for rule evaluations skipped under memory pressure --- rules/group.go | 13 ++++++++++++- rules/manager_test.go | 4 ++-- 2 files changed, 14 insertions(+), 3 deletions(-) diff --git a/rules/group.go b/rules/group.go index c805c439e84..7afe1798981 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 @@ -530,7 +531,7 @@ func (g *Group) Eval(ctx context.Context, ts time.Time) { if _, isAlert := rule.(*AlertingRule); !isAlert { if g.opts.MemoryLimiter != nil && !g.opts.MemoryLimiter.AllowRecordingRules() { - g.metrics.IterationsMissed.WithLabelValues(GroupKey(g.File(), g.Name())).Inc() + g.metrics.RulesSkipped.WithLabelValues(GroupKey(g.File(), g.Name())).Inc() return } } @@ -933,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, @@ -1058,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 { @@ -1077,6 +1087,7 @@ func NewGroupMetrics(reg prometheus.Registerer) *Metrics { m.GroupLastRestoreDuration, m.GroupRules, m.GroupSamples, + m.RulesSkipped, ) } diff --git a/rules/manager_test.go b/rules/manager_test.go index 1927f52a6ad..e7a5c136534 100644 --- a/rules/manager_test.go +++ b/rules/manager_test.go @@ -2875,8 +2875,8 @@ func TestGroup_MemoryLimiterRecordingRuleSkipping(t *testing.T) { // Run single evaluation cycle. group.Eval(context.Background(), time.Now()) - // 1. Verify recording rule was skipped (IterationsMissed incremented, no sample persisted). - require.Equal(t, float64(1), testutil.ToFloat64(opts.Metrics.IterationsMissed.WithLabelValues(GroupKey("test_file.yml", "test_group")))) + // 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") From 2b7534814a41c84ceeb017e1a7d62088a6b2d0b4 Mon Sep 17 00:00:00 2001 From: David Ashpole Date: Sat, 8 Aug 2026 02:13:37 +0000 Subject: [PATCH 51/72] Add Go doc comments for exported symbols in memorylimiter package --- util/memorylimiter/memory_limiter.go | 32 ++++++++++++++++++++++++++++ 1 file changed, 32 insertions(+) diff --git a/util/memorylimiter/memory_limiter.go b/util/memorylimiter/memory_limiter.go index e8549673d9e..e16aeae3b9c 100644 --- a/util/memorylimiter/memory_limiter.go +++ b/util/memorylimiter/memory_limiter.go @@ -27,14 +27,19 @@ import ( "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: @@ -48,20 +53,33 @@ func (s LimiterState) String() string { } } +// 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 + // AllowBlockCompaction returns true if block compaction is allowed. AllowBlockCompaction() 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 @@ -70,6 +88,7 @@ type MemoryStats struct { GCLimiterCycle uint64 } +// MetricsReader is a function that retrieves current runtime memory statistics. type MetricsReader func() MemoryStats func defaultMetricsReader() MemoryStats { @@ -100,6 +119,7 @@ func defaultMetricsReader() MemoryStats { return stats } +// Manager implements MemoryLimiter by tracking runtime memory usage and enforcing limits. type Manager struct { logger *slog.Logger @@ -122,6 +142,7 @@ type Manager struct { wg sync.WaitGroup } +// NewManager initializes and returns a new Manager. func NewManager(cfg *config.MemoryLimiterConfig, logger *slog.Logger, reg prometheus.Registerer) (*Manager, error) { if logger == nil { logger = slog.Default() @@ -145,6 +166,7 @@ func NewManager(cfg *config.MemoryLimiterConfig, logger *slog.Logger, reg promet return m, nil } +// ApplyConfig updates the Manager configuration. func (m *Manager) ApplyConfig(cfg *config.MemoryLimiterConfig) error { m.mu.Lock() defer m.mu.Unlock() @@ -165,6 +187,7 @@ func (m *Manager) ApplyConfig(cfg *config.MemoryLimiterConfig) error { return nil } +// State returns the current LimiterState. func (m *Manager) State() LimiterState { if m == nil { return StateOK @@ -172,6 +195,7 @@ func (m *Manager) State() LimiterState { 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 { @@ -187,6 +211,7 @@ func (m *Manager) Start(ctx context.Context) { go m.run(loopCtx) } +// Stop stops the background memory monitoring loop. func (m *Manager) Stop() { m.mu.Lock() if m.cancel != nil { @@ -324,6 +349,7 @@ func (m *Manager) Evaluate() { m.metrics.inUseBytes.Set(float64(inUse)) } +// AllowScrape returns true if scraping targets is allowed. func (m *Manager) AllowScrape() bool { if m == nil { return true @@ -337,6 +363,7 @@ func (m *Manager) AllowScrape() bool { return LimiterState(m.state.Load()) < StateHardLimit } +// AllowOTLP returns true if OTLP ingestion is allowed. func (m *Manager) AllowOTLP() bool { if m == nil { return true @@ -350,6 +377,7 @@ func (m *Manager) AllowOTLP() bool { 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 @@ -363,6 +391,7 @@ func (m *Manager) AllowRemoteWrite() bool { 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 @@ -376,6 +405,7 @@ func (m *Manager) AllowRemoteRead() bool { return LimiterState(m.state.Load()) < StateSoftLimit } +// AllowFederation returns true if federation endpoints are allowed. func (m *Manager) AllowFederation() bool { if m == nil { return true @@ -389,6 +419,7 @@ func (m *Manager) AllowFederation() bool { return LimiterState(m.state.Load()) < StateSoftLimit } +// AllowBlockCompaction returns true if TSDB block compaction is allowed. func (m *Manager) AllowBlockCompaction() bool { if m == nil { return true @@ -402,6 +433,7 @@ func (m *Manager) AllowBlockCompaction() bool { 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 From a84e054a3152449183b46118465438e0214e39c6 Mon Sep 17 00:00:00 2001 From: David Ashpole Date: Sat, 8 Aug 2026 02:13:44 +0000 Subject: [PATCH 52/72] Safely map runtime metrics by name in defaultMetricsReader --- util/memorylimiter/memory_limiter.go | 30 +++++++++++++++------------- 1 file changed, 16 insertions(+), 14 deletions(-) diff --git a/util/memorylimiter/memory_limiter.go b/util/memorylimiter/memory_limiter.go index e16aeae3b9c..8bc5674a307 100644 --- a/util/memorylimiter/memory_limiter.go +++ b/util/memorylimiter/memory_limiter.go @@ -101,20 +101,22 @@ func defaultMetricsReader() MemoryStats { } metrics.Read(samples) var stats MemoryStats - if samples[0].Value.Kind() == metrics.KindUint64 { - stats.TotalBytes = samples[0].Value.Uint64() - } - if samples[1].Value.Kind() == metrics.KindUint64 { - stats.FreeBytes = samples[1].Value.Uint64() - } - if samples[2].Value.Kind() == metrics.KindUint64 { - stats.ReleasedBytes = samples[2].Value.Uint64() - } - if samples[3].Value.Kind() == metrics.KindUint64 { - stats.GOMEMLIMIT = samples[3].Value.Uint64() - } - if samples[4].Value.Kind() == metrics.KindUint64 { - stats.GCLimiterCycle = samples[4].Value.Uint64() + 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 } From facb8141f4b0f2843ef5130d41535423cff45917 Mon Sep 17 00:00:00 2001 From: David Ashpole Date: Sat, 8 Aug 2026 02:13:59 +0000 Subject: [PATCH 53/72] Add unit tests for MemoryLimiterConfig validation and unmarshaling --- config/config_test.go | 71 +++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 71 insertions(+) diff --git a/config/config_test.go b/config/config_test.go index f98e0acab00..df9c1b6521f 100644 --- a/config/config_test.go +++ b/config/config_test.go @@ -3588,3 +3588,74 @@ 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, + }, + } + + 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) + } + }) + } +} From 357a9883e39a54a5e53194c8ef84458e27706748 Mon Sep 17 00:00:00 2001 From: David Ashpole Date: Sat, 8 Aug 2026 02:14:21 +0000 Subject: [PATCH 54/72] Update target scrapes skipped metric name to follow exceeded limit pattern --- scrape/metrics.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scrape/metrics.go b/scrape/metrics.go index 0418213e01b..a42a7f85fa5 100644 --- a/scrape/metrics.go +++ b/scrape/metrics.go @@ -266,7 +266,7 @@ func newScrapeMetrics(reg prometheus.Registerer) (*scrapeMetrics, error) { sm.targetScrapesSkipped = prometheus.NewCounter( prometheus.CounterOpts{ - Name: "prometheus_target_scrapes_skipped_total", + Name: "prometheus_target_scrapes_exceeded_memory_limit_total", Help: "Total number of target scrapes skipped due to memory limits.", }, ) From 08767729a356f2911e7f670b9f37a4c4cff5c8eb Mon Sep 17 00:00:00 2001 From: David Ashpole Date: Sat, 8 Aug 2026 02:14:45 +0000 Subject: [PATCH 55/72] Return structured JSON response for OTLP write memory limit rejection --- web/api/v1/api.go | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/web/api/v1/api.go b/web/api/v1/api.go index 246b1f5bc3c..a7aabbe9f03 100644 --- a/web/api/v1/api.go +++ b/web/api/v1/api.go @@ -2125,7 +2125,12 @@ 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) + w.Header().Set("Content-Type", "application/json") + w.WriteHeader(http.StatusServiceUnavailable) + _ = json.NewEncoder(w).Encode(map[string]any{ + "code": http.StatusServiceUnavailable, + "message": "Service Unavailable: Memory limit exceeded", + }) return } if api.otlpWriteHandler != nil { From b15cfea51f15378c186b7b6f1f61b5701688b7b4 Mon Sep 17 00:00:00 2001 From: David Ashpole Date: Sat, 8 Aug 2026 02:15:23 +0000 Subject: [PATCH 56/72] Update generated CLI documentation for memory-limiter feature flag --- docs/command-line/prometheus.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) 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` | From 1c738093dba9770278612d2cb1b11d78e797c764 Mon Sep 17 00:00:00 2001 From: David Ashpole Date: Sat, 8 Aug 2026 02:15:47 +0000 Subject: [PATCH 57/72] Add memory-limiter entry to docs/feature_flags.md --- docs/feature_flags.md | 7 +++++++ 1 file changed, 7 insertions(+) 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. + From 8295f9c8fe2c2da4d9c4d6bc4219844b88345ecd Mon Sep 17 00:00:00 2001 From: David Ashpole Date: Sat, 8 Aug 2026 02:22:24 +0000 Subject: [PATCH 58/72] Initialize DefaultMemoryLimiterConfig on DefaultRuntimeConfig --- config/config.go | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/config/config.go b/config/config.go index 5cd0e7426ab..01263c3a71f 100644 --- a/config/config.go +++ b/config/config.go @@ -193,7 +193,8 @@ var ( DefaultRuntimeConfig = RuntimeConfig{ // Go runtime tuning. - GoGC: getGoGC(), + GoGC: getGoGC(), + MemoryLimiter: DefaultMemoryLimiterConfig, } DefaultMemoryLimiterConfig = MemoryLimiterConfig{ From 63914ae8d1aa8a670c7b92d3d8aa7786ebf78920 Mon Sep 17 00:00:00 2001 From: David Ashpole Date: Sat, 8 Aug 2026 02:22:51 +0000 Subject: [PATCH 59/72] Check MemoryLimiter before deferring evaluation metrics in recording rules --- rules/group.go | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/rules/group.go b/rules/group.go index 7afe1798981..236289b6edc 100644 --- a/rules/group.go +++ b/rules/group.go @@ -513,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) { @@ -529,13 +536,6 @@ func (g *Group) Eval(ctx context.Context, ts time.Time) { logger = logger.With("trace_id", sp.SpanContext().TraceID()) } - 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 - } - } - g.metrics.EvalTotal.WithLabelValues(GroupKey(g.File(), g.Name())).Inc() vector, err := rule.Eval(ctx, ruleQueryOffset, ts, g.opts.QueryFunc, g.opts.ExternalURL, g.Limit()) From 221a7e3ec2480acfcd57a86833bfc3af0fdc4b17 Mon Sep 17 00:00:00 2001 From: David Ashpole Date: Sat, 8 Aug 2026 02:23:58 +0000 Subject: [PATCH 60/72] Unexport memoryStats and metricsReader, and update lastCheckTime in Evaluate --- util/memorylimiter/memory_limiter.go | 15 ++++++++------- util/memorylimiter/memory_limiter_test.go | 6 +++--- 2 files changed, 11 insertions(+), 10 deletions(-) diff --git a/util/memorylimiter/memory_limiter.go b/util/memorylimiter/memory_limiter.go index 8bc5674a307..80762417e1c 100644 --- a/util/memorylimiter/memory_limiter.go +++ b/util/memorylimiter/memory_limiter.go @@ -79,8 +79,8 @@ type MemoryLimiter interface { Stop() } -// MemoryStats holds runtime memory statistics used by MemoryLimiter. -type MemoryStats struct { +// memoryStats holds runtime memory statistics used by MemoryLimiter. +type memoryStats struct { TotalBytes uint64 FreeBytes uint64 ReleasedBytes uint64 @@ -88,10 +88,10 @@ type MemoryStats struct { GCLimiterCycle uint64 } -// MetricsReader is a function that retrieves current runtime memory statistics. -type MetricsReader func() MemoryStats +// metricsReader is a function that retrieves current runtime memory statistics. +type metricsReader func() memoryStats -func defaultMetricsReader() MemoryStats { +func defaultMetricsReader() memoryStats { samples := []metrics.Sample{ {Name: "/memory/classes/total:bytes"}, {Name: "/memory/classes/heap/free:bytes"}, @@ -100,7 +100,7 @@ func defaultMetricsReader() MemoryStats { {Name: "/gc/limiter/last-enabled:gc-cycle"}, } metrics.Read(samples) - var stats MemoryStats + var stats memoryStats for _, s := range samples { if s.Value.Kind() != metrics.KindUint64 { continue @@ -134,7 +134,7 @@ type Manager struct { gcLimiterInitialized bool lastCheckTime time.Time - metricsReader MetricsReader + metricsReader metricsReader now func() time.Time metrics *memoryLimiterMetrics @@ -272,6 +272,7 @@ func (m *Manager) Evaluate() { 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() diff --git a/util/memorylimiter/memory_limiter_test.go b/util/memorylimiter/memory_limiter_test.go index 9311aba9cc0..0822133f22d 100644 --- a/util/memorylimiter/memory_limiter_test.go +++ b/util/memorylimiter/memory_limiter_test.go @@ -26,9 +26,9 @@ import ( "github.com/prometheus/prometheus/config" ) -func newMockMetricsReader(total, released, gomemlimit, gcLimiterCycle uint64) MetricsReader { - return func() MemoryStats { - return MemoryStats{ +func newMockMetricsReader(total, released, gomemlimit, gcLimiterCycle uint64) metricsReader { + return func() memoryStats { + return memoryStats{ TotalBytes: total, ReleasedBytes: released, GOMEMLIMIT: gomemlimit, From 1e58ea08d56362fc64a40ebd5cb6bc9a080594ed Mon Sep 17 00:00:00 2001 From: David Ashpole Date: Sat, 8 Aug 2026 02:24:29 +0000 Subject: [PATCH 61/72] Use gRPC status code 14 for OTLP HTTP error payload --- web/api/v1/api.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/web/api/v1/api.go b/web/api/v1/api.go index a7aabbe9f03..749ab423837 100644 --- a/web/api/v1/api.go +++ b/web/api/v1/api.go @@ -2128,7 +2128,7 @@ func (api *API) otlpWrite(w http.ResponseWriter, r *http.Request) { w.Header().Set("Content-Type", "application/json") w.WriteHeader(http.StatusServiceUnavailable) _ = json.NewEncoder(w).Encode(map[string]any{ - "code": http.StatusServiceUnavailable, + "code": 14, "message": "Service Unavailable: Memory limit exceeded", }) return From b780c3b1e26b7b2d69713ca0abdb64862f1964b9 Mon Sep 17 00:00:00 2001 From: David Ashpole Date: Sat, 8 Aug 2026 02:33:10 +0000 Subject: [PATCH 62/72] Update expectedConf.Runtime in config_test.go to include DefaultMemoryLimiterConfig --- config/config_test.go | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/config/config_test.go b/config/config_test.go index df9c1b6521f..c9ccea9ddc2 100644 --- a/config/config_test.go +++ b/config/config_test.go @@ -113,7 +113,8 @@ var expectedConf = &Config{ }, Runtime: RuntimeConfig{ - GoGC: globalGoGC, + GoGC: globalGoGC, + MemoryLimiter: DefaultMemoryLimiterConfig, }, RuleFiles: []string{ From a42a7130182737b8eb1e44e8193c047a3f2068dc Mon Sep 17 00:00:00 2001 From: David Ashpole Date: Sat, 8 Aug 2026 02:33:41 +0000 Subject: [PATCH 63/72] Add full stops to MemoryLimiterEnforcement section comments per AGENTS.md --- config/config.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/config/config.go b/config/config.go index 01263c3a71f..0dbdc4b3376 100644 --- a/config/config.go +++ b/config/config.go @@ -766,12 +766,12 @@ type MemoryLimiterConfig struct { // MemoryLimiterEnforcement configures which mitigations are enabled. type MemoryLimiterEnforcement struct { - // Soft Limit mitigations + // Soft Limit mitigations. PauseBlockCompaction bool `yaml:"pause_block_compaction,omitempty"` RejectRemoteRead bool `yaml:"reject_remote_read,omitempty"` RejectFederation bool `yaml:"reject_federation,omitempty"` - // Hard Limit mitigations + // Hard Limit mitigations. FailScrapes bool `yaml:"fail_scrapes,omitempty"` RejectOTLP bool `yaml:"reject_otlp,omitempty"` RejectRemoteWrite bool `yaml:"reject_remote_write,omitempty"` From 53a76083ca1028339a77ea59438a3342f90a4cf8 Mon Sep 17 00:00:00 2001 From: David Ashpole Date: Thu, 13 Aug 2026 19:05:30 +0000 Subject: [PATCH 64/72] Fix failing unit tests --- rules/manager_test.go | 26 +++++++++++++------------- scrape/scrape_test.go | 20 ++++++++++---------- util/memorylimiter/memory_limiter.go | 22 +++++++++++++--------- 3 files changed, 36 insertions(+), 32 deletions(-) diff --git a/rules/manager_test.go b/rules/manager_test.go index e7a5c136534..ea9a062eb1b 100644 --- a/rules/manager_test.go +++ b/rules/manager_test.go @@ -2815,30 +2815,30 @@ type mockRuleMemoryLimiter struct { allowRecordingRules bool } -func (m *mockRuleMemoryLimiter) State() memorylimiter.LimiterState { +func (*mockRuleMemoryLimiter) State() memorylimiter.LimiterState { return memorylimiter.StateHardLimit } -func (m *mockRuleMemoryLimiter) AllowScrape() bool { return true } -func (m *mockRuleMemoryLimiter) AllowOTLP() bool { return true } -func (m *mockRuleMemoryLimiter) AllowRemoteWrite() bool { return true } -func (m *mockRuleMemoryLimiter) AllowRemoteRead() bool { return true } -func (m *mockRuleMemoryLimiter) AllowFederation() bool { return true } -func (m *mockRuleMemoryLimiter) AllowBlockCompaction() bool { return true } -func (m *mockRuleMemoryLimiter) AllowRecordingRules() bool { return m.allowRecordingRules } -func (m *mockRuleMemoryLimiter) ApplyConfig(*config.MemoryLimiterConfig) error { return nil } -func (m *mockRuleMemoryLimiter) Start(context.Context) {} -func (m *mockRuleMemoryLimiter) Stop() {} +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 (*mockRuleMemoryLimiter) AllowBlockCompaction() 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(ctx context.Context, expr string, alerts ...*Alert) { + notifyFunc := func(_ context.Context, _ string, _ ...*Alert) { alertFired.Store(true) } - queryFunc := func(ctx context.Context, q string, ts time.Time) (promql.Vector, error) { + queryFunc := func(_ context.Context, _ string, ts time.Time) (promql.Vector, error) { return promql.Vector{ promql.Sample{ Metric: labels.FromStrings("__name__", "up", "job", "test"), diff --git a/scrape/scrape_test.go b/scrape/scrape_test.go index df36c37ace9..35461240e87 100644 --- a/scrape/scrape_test.go +++ b/scrape/scrape_test.go @@ -7974,16 +7974,16 @@ func (m *mockMemoryLimiter) State() memorylimiter.LimiterState { } 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) AllowBlockCompaction() bool { return m.allowScrape } -func (m *mockMemoryLimiter) AllowRecordingRules() bool { return m.allowScrape } -func (m *mockMemoryLimiter) ApplyConfig(*config.MemoryLimiterConfig) error { return nil } -func (m *mockMemoryLimiter) Start(context.Context) {} -func (m *mockMemoryLimiter) Stop() {} +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) AllowBlockCompaction() 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} { diff --git a/util/memorylimiter/memory_limiter.go b/util/memorylimiter/memory_limiter.go index 80762417e1c..064656c802a 100644 --- a/util/memorylimiter/memory_limiter.go +++ b/util/memorylimiter/memory_limiter.go @@ -20,10 +20,11 @@ import ( "math" "runtime/metrics" "sync" - "sync/atomic" "time" "github.com/prometheus/client_golang/prometheus" + "go.uber.org/atomic" + "github.com/prometheus/prometheus/config" ) @@ -300,9 +301,10 @@ func (m *Manager) Evaluate() { oldState := LimiterState(m.state.Load()) if elapsed > 0 { - if oldState == StateSoftLimit { + switch oldState { + case StateSoftLimit: m.metrics.engagedSecondsTotal.WithLabelValues("soft").Add(elapsed) - } else if oldState == StateHardLimit { + case StateHardLimit: m.metrics.engagedSecondsTotal.WithLabelValues("hard").Add(elapsed) } } @@ -314,11 +316,12 @@ func (m *Manager) Evaluate() { m.gcLimiterInitialized = true var newState LimiterState - if pressureRatio >= m.config.HardLimitRatio || gcLimiterActive { + switch { + case pressureRatio >= m.config.HardLimitRatio || gcLimiterActive: newState = StateHardLimit - } else if pressureRatio >= m.config.SoftLimitRatio { + case pressureRatio >= m.config.SoftLimitRatio: newState = StateSoftLimit - } else { + default: newState = StateOK } @@ -336,13 +339,14 @@ func (m *Manager) Evaluate() { } // Update gauges. - if newState == StateHardLimit { + switch newState { + case StateHardLimit: m.metrics.active.WithLabelValues("hard").Set(1) m.metrics.active.WithLabelValues("soft").Set(1) - } else if newState == StateSoftLimit { + case StateSoftLimit: m.metrics.active.WithLabelValues("hard").Set(0) m.metrics.active.WithLabelValues("soft").Set(1) - } else { + default: m.metrics.active.WithLabelValues("hard").Set(0) m.metrics.active.WithLabelValues("soft").Set(0) } From c876dd3cc77d8eb9049f9bab9744597bbe79e29d Mon Sep 17 00:00:00 2001 From: David Ashpole Date: Thu, 13 Aug 2026 19:05:43 +0000 Subject: [PATCH 65/72] Address review comment: add to waitgroup while holding lock in Start --- util/memorylimiter/memory_limiter.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/util/memorylimiter/memory_limiter.go b/util/memorylimiter/memory_limiter.go index 064656c802a..8db4840ca4a 100644 --- a/util/memorylimiter/memory_limiter.go +++ b/util/memorylimiter/memory_limiter.go @@ -208,9 +208,9 @@ func (m *Manager) Start(ctx context.Context) { loopCtx, cancel := context.WithCancel(ctx) m.cancel = cancel m.lastCheckTime = m.now() + m.wg.Add(1) m.mu.Unlock() - m.wg.Add(1) go m.run(loopCtx) } From 19edc5dec30973f1e8a714f42dbff722d5e425f6 Mon Sep 17 00:00:00 2001 From: David Ashpole Date: Thu, 13 Aug 2026 19:05:56 +0000 Subject: [PATCH 66/72] Address review comment: accumulate soft limit engaged seconds during hard limit --- util/memorylimiter/memory_limiter.go | 1 + 1 file changed, 1 insertion(+) diff --git a/util/memorylimiter/memory_limiter.go b/util/memorylimiter/memory_limiter.go index 8db4840ca4a..0b72f005555 100644 --- a/util/memorylimiter/memory_limiter.go +++ b/util/memorylimiter/memory_limiter.go @@ -305,6 +305,7 @@ func (m *Manager) Evaluate() { 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) } } From 63bfad73c78c7377d2eee53d8d302bc049fa81c6 Mon Sep 17 00:00:00 2001 From: David Ashpole Date: Thu, 13 Aug 2026 19:06:06 +0000 Subject: [PATCH 67/72] Address review comment: validate config before registering metrics in NewManager --- util/memorylimiter/memory_limiter.go | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/util/memorylimiter/memory_limiter.go b/util/memorylimiter/memory_limiter.go index 0b72f005555..ca93cbaa6bb 100644 --- a/util/memorylimiter/memory_limiter.go +++ b/util/memorylimiter/memory_limiter.go @@ -147,6 +147,12 @@ type Manager struct { // 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() } @@ -160,12 +166,6 @@ func NewManager(cfg *config.MemoryLimiterConfig, logger *slog.Logger, reg promet reloadCh: make(chan struct{}, 1), } - if cfg != nil { - if err := cfg.Validate(); err != nil { - return nil, fmt.Errorf("invalid memory limiter config: %w", err) - } - } - return m, nil } From b953dd914da0e6c65a59ee95bfec3391a8fe4d19 Mon Sep 17 00:00:00 2001 From: David Ashpole Date: Thu, 13 Aug 2026 19:06:55 +0000 Subject: [PATCH 68/72] Address review comment: require valid non-zero configuration in MemoryLimiterConfig.Validate --- config/config.go | 3 --- config/config_test.go | 9 +++++++++ 2 files changed, 9 insertions(+), 3 deletions(-) diff --git a/config/config.go b/config/config.go index 0dbdc4b3376..5c3e7cfa53c 100644 --- a/config/config.go +++ b/config/config.go @@ -791,9 +791,6 @@ func (e *MemoryLimiterEnforcement) isZero() bool { // Validate validates the memory limiter configuration. func (c *MemoryLimiterConfig) Validate() error { - if c.isZero() { - return nil - } if c.CheckInterval <= 0 { return errors.New("memory_limiter check_interval must be greater than 0") } diff --git a/config/config_test.go b/config/config_test.go index c9ccea9ddc2..d991d75937b 100644 --- a/config/config_test.go +++ b/config/config_test.go @@ -3640,6 +3640,15 @@ hard_limit_ratio: 1.5 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, }, From 33fb66fcc388dd78a139855547305c6933c2e6c7 Mon Sep 17 00:00:00 2001 From: David Ashpole Date: Thu, 13 Aug 2026 19:09:13 +0000 Subject: [PATCH 69/72] Address review comment: remove unused PauseBlockCompaction and AllowBlockCompaction until TSDB integration is implemented --- config/config.go | 20 +++++++++----------- rules/manager_test.go | 1 - scrape/scrape_test.go | 1 - util/memorylimiter/memory_limiter.go | 16 ---------------- util/memorylimiter/memory_limiter_test.go | 17 ++++++----------- 5 files changed, 15 insertions(+), 40 deletions(-) diff --git a/config/config.go b/config/config.go index 5c3e7cfa53c..867459d4477 100644 --- a/config/config.go +++ b/config/config.go @@ -205,13 +205,12 @@ var ( } DefaultMemoryLimiterEnforcement = MemoryLimiterEnforcement{ - PauseBlockCompaction: true, - RejectRemoteRead: true, - RejectFederation: true, - FailScrapes: true, - RejectOTLP: true, - RejectRemoteWrite: true, - PauseRecordingRules: true, + RejectRemoteRead: true, + RejectFederation: true, + FailScrapes: true, + RejectOTLP: true, + RejectRemoteWrite: true, + PauseRecordingRules: true, } // DefaultScrapeConfig is the default scrape configuration. Users of this @@ -767,9 +766,8 @@ type MemoryLimiterConfig struct { // MemoryLimiterEnforcement configures which mitigations are enabled. type MemoryLimiterEnforcement struct { // Soft Limit mitigations. - PauseBlockCompaction bool `yaml:"pause_block_compaction,omitempty"` - RejectRemoteRead bool `yaml:"reject_remote_read,omitempty"` - RejectFederation bool `yaml:"reject_federation,omitempty"` + RejectRemoteRead bool `yaml:"reject_remote_read,omitempty"` + RejectFederation bool `yaml:"reject_federation,omitempty"` // Hard Limit mitigations. FailScrapes bool `yaml:"fail_scrapes,omitempty"` @@ -785,7 +783,7 @@ func (c *MemoryLimiterConfig) isZero() bool { // isZero returns true iff the enforcement config is the zero value. func (e *MemoryLimiterEnforcement) isZero() bool { - return !e.PauseBlockCompaction && !e.RejectRemoteRead && !e.RejectFederation && + return !e.RejectRemoteRead && !e.RejectFederation && !e.FailScrapes && !e.RejectOTLP && !e.RejectRemoteWrite && !e.PauseRecordingRules } diff --git a/rules/manager_test.go b/rules/manager_test.go index ea9a062eb1b..14aabaed252 100644 --- a/rules/manager_test.go +++ b/rules/manager_test.go @@ -2823,7 +2823,6 @@ func (*mockRuleMemoryLimiter) AllowOTLP() bool { r func (*mockRuleMemoryLimiter) AllowRemoteWrite() bool { return true } func (*mockRuleMemoryLimiter) AllowRemoteRead() bool { return true } func (*mockRuleMemoryLimiter) AllowFederation() bool { return true } -func (*mockRuleMemoryLimiter) AllowBlockCompaction() bool { return true } func (m *mockRuleMemoryLimiter) AllowRecordingRules() bool { return m.allowRecordingRules } func (*mockRuleMemoryLimiter) ApplyConfig(*config.MemoryLimiterConfig) error { return nil } func (*mockRuleMemoryLimiter) Start(context.Context) {} diff --git a/scrape/scrape_test.go b/scrape/scrape_test.go index 35461240e87..7e95459dfc2 100644 --- a/scrape/scrape_test.go +++ b/scrape/scrape_test.go @@ -7979,7 +7979,6 @@ func (m *mockMemoryLimiter) AllowOTLP() bool { retur 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) AllowBlockCompaction() 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) {} diff --git a/util/memorylimiter/memory_limiter.go b/util/memorylimiter/memory_limiter.go index ca93cbaa6bb..b4cd53c5da9 100644 --- a/util/memorylimiter/memory_limiter.go +++ b/util/memorylimiter/memory_limiter.go @@ -68,8 +68,6 @@ type MemoryLimiter interface { AllowRemoteRead() bool // AllowFederation returns true if federation requests are allowed. AllowFederation() bool - // AllowBlockCompaction returns true if block compaction is allowed. - AllowBlockCompaction() bool // AllowRecordingRules returns true if recording rules evaluation is allowed. AllowRecordingRules() bool // ApplyConfig updates the memory limiter configuration. @@ -427,20 +425,6 @@ func (m *Manager) AllowFederation() bool { return LimiterState(m.state.Load()) < StateSoftLimit } -// AllowBlockCompaction returns true if TSDB block compaction is allowed. -func (m *Manager) AllowBlockCompaction() bool { - if m == nil { - return true - } - m.mu.RLock() - cfg := m.config - m.mu.RUnlock() - if cfg == nil || !cfg.Enforcement.PauseBlockCompaction { - 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 { diff --git a/util/memorylimiter/memory_limiter_test.go b/util/memorylimiter/memory_limiter_test.go index 0822133f22d..21493490c0b 100644 --- a/util/memorylimiter/memory_limiter_test.go +++ b/util/memorylimiter/memory_limiter_test.go @@ -43,13 +43,12 @@ func TestMemoryLimiterStateTransitions(t *testing.T) { SoftLimitRatio: 0.70, HardLimitRatio: 0.85, Enforcement: config.MemoryLimiterEnforcement{ - PauseBlockCompaction: true, - RejectRemoteRead: true, - RejectFederation: true, - FailScrapes: true, - RejectOTLP: true, - RejectRemoteWrite: true, - PauseRecordingRules: true, + RejectRemoteRead: true, + RejectFederation: true, + FailScrapes: true, + RejectOTLP: true, + RejectRemoteWrite: true, + PauseRecordingRules: true, }, } @@ -71,7 +70,6 @@ func TestMemoryLimiterStateTransitions(t *testing.T) { require.True(t, mgr.AllowRemoteWrite()) require.True(t, mgr.AllowRemoteRead()) require.True(t, mgr.AllowFederation()) - require.True(t, mgr.AllowBlockCompaction()) require.True(t, mgr.AllowRecordingRules()) // 2. Soft limit state: 750 MB in-use (75% ratio >= 70%, < 85%) @@ -84,7 +82,6 @@ func TestMemoryLimiterStateTransitions(t *testing.T) { require.True(t, mgr.AllowRemoteWrite()) require.False(t, mgr.AllowRemoteRead()) require.False(t, mgr.AllowFederation()) - require.False(t, mgr.AllowBlockCompaction()) require.True(t, mgr.AllowRecordingRules()) // 3. Hard limit state: 900 MB in-use (90% ratio >= 85%) @@ -97,7 +94,6 @@ func TestMemoryLimiterStateTransitions(t *testing.T) { require.False(t, mgr.AllowRemoteWrite()) require.False(t, mgr.AllowRemoteRead()) require.False(t, mgr.AllowFederation()) - require.False(t, mgr.AllowBlockCompaction()) require.False(t, mgr.AllowRecordingRules()) // 4. Memory drops back to 400 MB (40% < 70%) -> Clean recovery to StateOK @@ -106,7 +102,6 @@ func TestMemoryLimiterStateTransitions(t *testing.T) { mgr.Evaluate() require.Equal(t, StateOK, mgr.State()) require.True(t, mgr.AllowScrape()) - require.True(t, mgr.AllowBlockCompaction()) } func TestGCLimiterEscalation(t *testing.T) { From 235a77923c595a0294c4467008602d4b3180c220 Mon Sep 17 00:00:00 2001 From: David Ashpole Date: Thu, 13 Aug 2026 19:10:04 +0000 Subject: [PATCH 70/72] Address review comment: return standard http.Error for OTLP write memory limit rejection --- web/api/v1/api.go | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/web/api/v1/api.go b/web/api/v1/api.go index 749ab423837..246b1f5bc3c 100644 --- a/web/api/v1/api.go +++ b/web/api/v1/api.go @@ -2125,12 +2125,7 @@ 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") - w.Header().Set("Content-Type", "application/json") - w.WriteHeader(http.StatusServiceUnavailable) - _ = json.NewEncoder(w).Encode(map[string]any{ - "code": 14, - "message": "Service Unavailable: Memory limit exceeded", - }) + http.Error(w, "Service Unavailable: Memory limit exceeded", http.StatusServiceUnavailable) return } if api.otlpWriteHandler != nil { From 2fa1fdeeb31131c9d8a35a31be5d2d4ba8415f44 Mon Sep 17 00:00:00 2001 From: David Ashpole Date: Thu, 13 Aug 2026 19:10:18 +0000 Subject: [PATCH 71/72] Address review comment: restore missing comment sentence in scrape options --- scrape/manager.go | 1 + 1 file changed, 1 insertion(+) diff --git a/scrape/manager.go b/scrape/manager.go index f9d9fec3d7e..6e427db3d14 100644 --- a/scrape/manager.go +++ b/scrape/manager.go @@ -176,6 +176,7 @@ type Options struct { // initialized immediately upon startup. It also prevents capturing // intermediate state (such as applications crashing shortly after booting), // and ensures backend rate limits don't drop valuable shutdown scrapes + // because of an early startup scrape. InitialScrapeOffset time.Duration // Optional memory limiter to abort scrapes under memory pressure. From 33955d283c3a073df74672266df420e812ca9977 Mon Sep 17 00:00:00 2001 From: David Ashpole Date: Thu, 13 Aug 2026 19:10:42 +0000 Subject: [PATCH 72/72] Address review comment: clarify ratio error message as inclusive --- config/config.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/config/config.go b/config/config.go index 867459d4477..9df07a2d6fa 100644 --- a/config/config.go +++ b/config/config.go @@ -793,10 +793,10 @@ func (c *MemoryLimiterConfig) Validate() error { 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 (exclusive), got %f", c.SoftLimitRatio) + 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 (exclusive), got %f", c.HardLimitRatio) + 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)