diff --git a/async/async-commons/async-commons.gradle b/async/async-commons/async-commons.gradle index 381b446b..62e9c5e7 100644 --- a/async/async-commons/async-commons.gradle +++ b/async/async-commons/async-commons.gradle @@ -10,8 +10,8 @@ dependencies { compileOnly 'io.projectreactor:reactor-core' api 'tools.jackson.core:jackson-databind' - implementation 'commons-io:commons-io:2.21.0' - implementation 'io.cloudevents:cloudevents-core:4.0.1' + implementation 'commons-io:commons-io:2.22.0' + implementation 'io.cloudevents:cloudevents-core:4.0.2' testImplementation 'io.projectreactor:reactor-test' } \ No newline at end of file diff --git a/async/async-kafka/async-kafka.gradle b/async/async-kafka/async-kafka.gradle index 3f7af8b6..056191a8 100644 --- a/async/async-kafka/async-kafka.gradle +++ b/async/async-kafka/async-kafka.gradle @@ -9,5 +9,5 @@ dependencies { api project(':async-commons') api project(':cloudevents-json-jackson') api 'io.projectreactor.kafka:reactor-kafka:1.3.25' - implementation 'io.cloudevents:cloudevents-core:4.0.1' + implementation 'io.cloudevents:cloudevents-core:4.0.2' } \ No newline at end of file diff --git a/async/async-rabbit/async-rabbit.gradle b/async/async-rabbit/async-rabbit.gradle index dde69636..f9f000c8 100644 --- a/async/async-rabbit/async-rabbit.gradle +++ b/async/async-rabbit/async-rabbit.gradle @@ -15,6 +15,6 @@ dependencies { api 'com.rabbitmq:amqp-client' api 'tools.jackson.core:jackson-databind' - implementation 'io.cloudevents:cloudevents-core:4.0.1' + implementation 'io.cloudevents:cloudevents-core:4.0.2' testImplementation 'io.projectreactor:reactor-test' } \ No newline at end of file diff --git a/async/async-rabbit/src/main/java/org/reactivecommons/async/rabbit/listeners/GenericMessageListener.java b/async/async-rabbit/src/main/java/org/reactivecommons/async/rabbit/listeners/GenericMessageListener.java index dac167ff..4e2a8e46 100644 --- a/async/async-rabbit/src/main/java/org/reactivecommons/async/rabbit/listeners/GenericMessageListener.java +++ b/async/async-rabbit/src/main/java/org/reactivecommons/async/rabbit/listeners/GenericMessageListener.java @@ -9,15 +9,15 @@ import org.reactivecommons.async.commons.utils.LoggerSubscriber; import org.reactivecommons.async.rabbit.InstanceIdentifier; import org.reactivecommons.async.rabbit.RabbitMessage; -import reactor.rabbitmq.AcknowledgableDelivery; -import reactor.rabbitmq.ConsumeOptions; import org.reactivecommons.async.rabbit.communications.ReactiveMessageListener; import org.reactivecommons.async.rabbit.communications.TopologyCreator; -import reactor.rabbitmq.Receiver; import reactor.core.publisher.Flux; import reactor.core.publisher.Mono; import reactor.core.scheduler.Scheduler; import reactor.core.scheduler.Schedulers; +import reactor.rabbitmq.AcknowledgableDelivery; +import reactor.rabbitmq.ConsumeOptions; +import reactor.rabbitmq.Receiver; import reactor.util.retry.Retry; import java.time.Duration; @@ -93,9 +93,18 @@ public void startListener() { log.log(Level.INFO, "ATTENTION! Using infinite fast retries as Retry Strategy"); } - ConsumeOptions consumeOptions = new ConsumeOptions(); - consumeOptions.qos(messageListener.prefetchCount()); - consumeOptions.consumerTag(InstanceIdentifier.getInstanceId(getKind())); + ConsumeOptions consumeOptions = new ConsumeOptions() + .qos(messageListener.prefetchCount()) + .consumerTag(InstanceIdentifier.getInstanceId(getKind())) + .channelCallback(channel -> channel.addShutdownListener(cause -> { + log.log(Level.WARNING, cause, () -> "Channel shutdown detected in queue " + queueName + + " channel open: " + channel.isOpen() + + " connection open: " + channel.getConnection().isOpen()); + if (channel.getConnection().isOpen() && !channel.isOpen()) { + log.warning("Recovering listener for queue: " + queueName); + onTerminate(); + } + })); if (createTopology) { this.messageFlux = setUpBindings(messageListener.topologyCreator()) diff --git a/async/cloudevents-json-jackson/cloudevents-json-jackson.gradle b/async/cloudevents-json-jackson/cloudevents-json-jackson.gradle index 161f122a..35378387 100644 --- a/async/cloudevents-json-jackson/cloudevents-json-jackson.gradle +++ b/async/cloudevents-json-jackson/cloudevents-json-jackson.gradle @@ -5,6 +5,6 @@ ext { dependencies { api 'tools.jackson.core:jackson-databind' - implementation 'io.cloudevents:cloudevents-api:4.0.1' - implementation 'io.cloudevents:cloudevents-core:4.0.1' + implementation 'io.cloudevents:cloudevents-api:4.0.2' + implementation 'io.cloudevents:cloudevents-core:4.0.2' } \ No newline at end of file diff --git a/build.gradle b/build.gradle index 0e1a8333..fa6c2298 100644 --- a/build.gradle +++ b/build.gradle @@ -12,10 +12,10 @@ buildscript { plugins { id 'jacoco' - id 'org.sonarqube' version '7.2.2.6593' - id 'org.springframework.boot' version '4.0.4' apply false + id 'org.sonarqube' version '7.3.0.8198' + id 'org.springframework.boot' version '4.0.6' apply false id 'io.github.gradle-nexus.publish-plugin' version '2.0.0' - id 'co.com.bancolombia.cleanArchitecture' version '4.3.0' + id 'co.com.bancolombia.cleanArchitecture' version '4.4.1' } repositories { diff --git a/docs/docs/reactive-commons/configuration_properties/1-rabbitmq.md b/docs/docs/reactive-commons/configuration_properties/1-rabbitmq.md index 665f8069..d4a136ad 100644 --- a/docs/docs/reactive-commons/configuration_properties/1-rabbitmq.md +++ b/docs/docs/reactive-commons/configuration_properties/1-rabbitmq.md @@ -4,13 +4,18 @@ sidebar_position: 1 # RabbitMQ Configuration -You can customize some predefined variables of Reactive Commons. - -This can be done by Spring Boot `application.yaml` or by overriding -the [AsyncProps](https://github.com/reactive-commons/reactive-commons-java/blob/master/starters/async-rabbit-starter/src/main/java/org/reactivecommons/async/rabbit/config/props/AsyncProps.java) -bean. - -```yaml +This page describes how to configure RabbitMQ connection and messaging properties for each **domain** in +Reactive Commons. A domain represents an independent connection to a RabbitMQ broker. Your application can work +with a single domain (one broker) or multiple domains (several independent brokers), each with its own properties. +See [Communication Scenarios](/reactive-commons-java/docs/category/communication-scenarios) for guidance on when +to use multiple domains. + +All available properties are defined in the +[AsyncProps](https://github.com/reactive-commons/reactive-commons-java/blob/master/starters/async-rabbit-starter/src/main/java/org/reactivecommons/async/rabbit/config/props/AsyncProps.java) +class. There are two ways to provide these values via `application.yaml` or a combination of YAML and +programmatic configuration, as described in the [Configuration approaches](#configuration-approaches) section below. + +```yaml title="application.yaml" app: async: app: # this is the name of the default domain @@ -58,135 +63,267 @@ app: virtual-host: /accounts ``` -You can override this settings programmatically through an `AsyncRabbitPropsDomainProperties` bean: - :::caution[Mandatory `app` Domain Configuration] To ensure a correct configuration, you should always override the properties of the `app` domain. If it is not configured, an exception will be thrown. You can also add properties for additional custom domain if needed. ::: +## Configuration approaches + +There are two ways to supply domain properties. Choose the one that best fits your use case. + +### Approach 1: YAML only + +Define all domains directly in `application.yaml` as shown above. This is the simplest approach and works well when +properties do not depend on runtime values such as secrets. + +### Approach 2: Hybrid YAML + `RabbitPropsCustomizer` + +Use this approach when you want to define the domain structure in YAML (topology, retry settings, etc.) but need to +set some properties at runtime for example, loading connection credentials from a secrets manager. + +Declare your domains in `application.yaml` as usual, then define a `RabbitPropsCustomizer` bean to override specific +properties after the YAML is loaded. The customizer receives the full map of configured domains and can modify +any property on any domain. + +:::caution[YAML domains are optional] +The `RabbitPropsCustomizer` can work with or without pre-existing YAML domains. If no domains are defined in your +`application.yaml` under `app.async`, you can define all domains directly inside the customizer using +`domainProperties.put("", AsyncProps.builder()...build())`. At least one domain must exist after the customizer +executes, otherwise an `InvalidConfigurationException` is thrown. +::: + +You have two options: + +**Option A: Define domains in YAML, then override with customizer** + +Declare your domains in `application.yaml` as usual, then use the customizer to override or extend them. + +```yaml title="application.yaml" +app: + async: + app: # first domain + withDLQRetry: true + maxRetries: 3 + listenReplies: true + accounts: # second domain + listenReplies: false +``` + ```java package sample; import org.reactivecommons.async.rabbit.config.RabbitProperties; import org.reactivecommons.async.rabbit.config.props.AsyncProps; -import org.reactivecommons.async.rabbit.config.props.AsyncRabbitPropsDomainProperties; +import org.reactivecommons.async.rabbit.config.props.AsyncPropsDomain; import org.springframework.context.annotation.Bean; -import org.springframework.context.annotation.Primary; +import org.springframework.context.annotation.Configuration; @Configuration -public class MyDomainConfig { +public class RabbitMQConfig { + + // Loads RabbitMQ connection properties from a secrets manager at runtime. + // See the "Loading properties from a secret" section below for a complete implementation example. + private RabbitProperties loadFromSecret(String secretName) { + // ... + return new RabbitProperties(); + } @Bean - @Primary - public AsyncRabbitPropsDomainProperties customDomainProperties() { - RabbitProperties propertiesApp = new RabbitProperties(); - propertiesApp.setHost("localhost"); - propertiesApp.setPort(5672); - propertiesApp.setVirtualHost("/"); - propertiesApp.setUsername("guest"); - propertiesApp.setPassword("guest"); - - RabbitProperties propertiesAccounts = new RabbitProperties(); - propertiesAccounts.setHost("localhost"); - propertiesAccounts.setPort(5672); - propertiesAccounts.setVirtualHost("/accounts"); - propertiesAccounts.setUsername("guest"); - propertiesAccounts.setPassword("guest"); + public AsyncPropsDomain.RabbitPropsCustomizer rabbitPropsCustomizer() { + return domainProperties -> { + // Customize the "app" domain — overrides take precedence over YAML values + AsyncProps app = domainProperties.get("app"); + if (app != null) { + app.setConnectionProperties(loadFromSecret("secret-app-rabbit")); + } - return AsyncRabbitPropsDomainProperties.builder() - .withDomain("app", AsyncProps.builder() - .connectionProperties(propertiesApp) - .build()) - .withDomain("accounts", AsyncProps.builder() - .connectionProperties(propertiesAccounts) - .build()) - .build(); + // Customize the "accounts" domain independently + AsyncProps accounts = domainProperties.get("accounts"); + if (accounts != null) { + accounts.setConnectionProperties(loadFromSecret("secret-accounts-rabbit")); + } + }; } } ``` -## Loading properties from a secret +**Option B: Define all domains in the customizer (no YAML domains)** -Additionally, if you want to set only connection properties you can use the `AsyncPropsDomain.RabbitSecretFiller` class. +If you prefer full programmatic control, **omit the `app.async` section entirely from your `application.yaml`** and +define all domains +inside the customizer: ```java +package sample; -@Bean -public AsyncPropsDomain.RabbitSecretFiller customFiller() { - return (domain, asyncProps) -> { - // customize asyncProps here by domain - }; +import org.reactivecommons.async.rabbit.config.RabbitProperties; +import org.reactivecommons.async.rabbit.config.props.AsyncProps; +import org.reactivecommons.async.rabbit.config.props.AsyncPropsDomain; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; + +@Configuration +public class RabbitMQConfig { + + private RabbitProperties loadFromSecret(String secretName) { + // ... + return new RabbitProperties(); + } + + @Bean + public AsyncPropsDomain.RabbitPropsCustomizer rabbitPropsCustomizer() { + return domainProperties -> { + // Define all domains programmatically + domainProperties.put("app", AsyncProps.builder() + .withDLQRetry(Boolean.TRUE) + .maxRetries(3) + .listenReplies(Boolean.TRUE) + .connectionProperties(loadFromSecret("secret-app-rabbit")) + .build()); + + domainProperties.put("accounts", AsyncProps.builder() + .listenReplies(Boolean.FALSE) + .connectionProperties(loadFromSecret("secret-accounts-rabbit")) + .build()); + }; + } } ``` -For example if you use the [Secrets Manager](https://github.com/bancolombia/secrets-manager) project, you may use -the next code to load the properties from a secret: +**Key rules for the hybrid approach:** + +- Properties set in the customizer **take precedence** over YAML values. +- YAML values not touched by the customizer are **preserved**. +- The customizer can also **add new domains** by calling `domainProperties.put("newDomain", asyncProps)`. + +## Loading properties from a secret + +:::danger[Deprecated] +Using `AsyncPropsDomain.RabbitSecretFiller` to load secrets is **deprecated** and will be removed in a future version. +Use **[Approach 2: Hybrid YAML + `RabbitPropsCustomizer`](#approach-2-hybrid-yaml--rabbitpropscustomizer)** instead, +which provides full control over all domain properties at runtime and is the recommended way to integrate with a +secrets manager. +::: + +The recommended way to load connection properties from a secrets manager is to use the `RabbitPropsCustomizer` (see +[Approach 2](#approach-2-hybrid-yaml--rabbitpropscustomizer)). This gives you full control over all domain properties +at runtime. The example below uses the [Secrets Manager](https://github.com/bancolombia/secrets-manager) library. + +1. Create a `@ConfigurationProperties` record to map the secret fields: + +```java +import org.springframework.boot.context.properties.ConfigurationProperties; + +@ConfigurationProperties(prefix = "helpers.secrets-manager") +public record SecretsManagerProperties( + String endpoint, + Integer cacheSize, + Integer cacheTime, + String rabbit) { +} +``` -1. Create a class with the properties that you will load from the secret: +2. Create a `RabbitMQConnectionProperties` record to map the fields of your secret and provide a conversion method: ```java -import lombok.Builder; -import lombok.Data; import org.reactivecommons.async.rabbit.config.RabbitProperties; -@Data -@Builder -public class RabbitConnectionProperties { - private String hostname; - private String password; - private String username; - private Integer port; - private String virtualhost; - private boolean ssl; +public record RabbitMQConnectionProperties( + String virtualhost, + String host, + String password, + String username, + boolean ssl, + Integer port) { public RabbitProperties toRabbitProperties() { var rabbitProperties = new RabbitProperties(); - rabbitProperties.setHost(this.hostname); - rabbitProperties.setUsername(this.username); - rabbitProperties.setPassword(this.password); - rabbitProperties.setPort(this.port); - rabbitProperties.setVirtualHost(this.virtualhost); - rabbitProperties.getSsl().setEnabled(this.ssl); // To enable SSL + rabbitProperties.setHost(this.host()); + rabbitProperties.setUsername(this.username()); + rabbitProperties.setPassword(this.password()); + rabbitProperties.setPort(this.port()); + rabbitProperties.setVirtualHost(this.virtualhost()); + rabbitProperties.getSsl().setEnabled(this.ssl()); // To enable SSL return rabbitProperties; } } ``` -2. Use the `SecretsManager` to load the properties from the secret: +3. Create a `SecretsConfig` class that registers the `GenericManager` bean and exposes the RabbitMQ secret as a bean: ```java import co.com.bancolombia.secretsmanager.api.GenericManager; -import lombok.SneakyThrows; +import co.com.bancolombia.secretsmanager.connector.AWSSecretManagerConnector; +import lombok.RequiredArgsConstructor; import lombok.extern.log4j.Log4j2; -import org.reactivecommons.async.rabbit.config.RabbitProperties; -import org.reactivecommons.async.rabbit.config.props.AsyncPropsDomain; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; - -import java.lang.reflect.GenericArrayType; +import org.springframework.context.annotation.Profile; +import software.amazon.awssdk.regions.Region; @Log4j2 @Configuration +@RequiredArgsConstructor +public class SecretsConfig { + + private final SecretsManagerProperties properties; + private static final String REGION_SECRET = Region.US_EAST_1.toString(); + + @Bean + @Profile("!local") + public GenericManager connectionAws() { + return new AWSSecretManagerConnector(REGION_SECRET); + } + + @Bean + @Profile("local") + public GenericManager connectionLocal() { + return new AWSSecretManagerConnector(REGION_SECRET, properties.endpoint()); + } + + public T getSecret(String secretName, Class cls, GenericManager connector) { + try { + log.info("Secret was obtained successfully"); + return connector.getSecret(secretName, cls); + } catch (Exception e) { + log.error("Error getting secret: {}", e.getMessage()); + return null; + } + } + + @Bean + public RabbitMQConnectionProperties getSecretRabbitmq(GenericManager connector) { + return this.getSecret(properties.rabbit(), RabbitMQConnectionProperties.class, connector); + } +} +``` + +4. Create a separate `RabbitMQConfig` class that injects the `RabbitMQConnectionProperties` bean and defines the + `RabbitPropsCustomizer`: + +```java +import lombok.RequiredArgsConstructor; +import org.reactivecommons.async.rabbit.config.props.AsyncProps; +import org.reactivecommons.async.rabbit.config.props.AsyncPropsDomain; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; + +@Configuration +@RequiredArgsConstructor public class RabbitMQConfig { - // TODO: You should create the GenericManager bean as indicated in Secrets Manager library + private final RabbitMQConnectionProperties rabbitMQConnectionProperties; + @Bean - public AsyncPropsDomain.RabbitSecretFiller rabbitSecretFiller(GenericManager genericManager) { - return (domain, props) -> { - if (props.getSecret() != null) { - log.info("Loading RabbitMQ connection properties from secret: {}", props.getSecret()); - props.setConnectionProperties(getFromSecret(genericManager, props.getSecret())); - log.info("RabbitMQ connection properties loaded successfully with host: '{}'", - props.getConnectionProperties().getHost()); + public AsyncPropsDomain.RabbitPropsCustomizer rabbitPropsCustomizer() { + return domainProperties -> { + AsyncProps app = domainProperties.get("app"); + if (app != null) { + app.setConnectionProperties(rabbitMQConnectionProperties.toRabbitProperties()); } }; } - - @SneakyThrows - private RabbitProperties getFromSecret(GenericManager genericManager, String secretName) { - return genericManager.getSecret(secretName, RabbitConnectionProperties.class).toRabbitProperties(); - } } ``` diff --git a/docs/docs/reactive-commons/configuration_properties/2-kafka.md b/docs/docs/reactive-commons/configuration_properties/2-kafka.md index 81917b22..c244a3ef 100644 --- a/docs/docs/reactive-commons/configuration_properties/2-kafka.md +++ b/docs/docs/reactive-commons/configuration_properties/2-kafka.md @@ -4,13 +4,18 @@ sidebar_position: 2 # Kafka Configuration -You can customize some predefined variables of Reactive Commons. +This page describes how to configure Kafka connection and messaging properties for each **domain** in +Reactive Commons. A domain represents an independent connection to a Kafka cluster. Your application can work +with a single domain (one cluster) or multiple domains (several independent clusters), each with its own properties. +See [Communication Scenarios](/reactive-commons-java/docs/category/communication-scenarios) for guidance on when +to use multiple domains. -This can be done by Spring Boot `application.yaml` or by overriding -the [AsyncKafkaProps](https://github.com/reactive-commons/reactive-commons-java/blob/master/starters/async-kafka-starter/src/main/java/org/reactivecommons/async/kafka/config/props/AsyncKafkaProps.java) -bean. +All available properties are defined in the +[AsyncKafkaProps](https://github.com/reactive-commons/reactive-commons-java/blob/master/starters/async-kafka-starter/src/main/java/org/reactivecommons/async/kafka/config/props/AsyncKafkaProps.java) +class. There are two ways to provide these values via `application.yaml` or a combination of YAML and +programmatic configuration, as described in the [Configuration approaches](#configuration-approaches) section below. -```yaml +```yaml title="application.yaml" reactive: commons: kafka: @@ -33,53 +38,254 @@ reactive: bootstrap-servers: localhost:9093 ``` -You can override this settings programmatically through a `AsyncKafkaPropsDomainProperties` bean: +## Configuration approaches + +There are two ways to supply domain properties. Choose the one that best fits your use case. + +### Approach 1: YAML only + +Define all domains directly in `application.yaml` as shown above. No additional Java configuration is needed. +This is the simplest approach and works well when properties do not depend on runtime values such as secrets. + +### Approach 2: Hybrid YAML + `KafkaPropsCustomizer` + +Use this approach when you want to define the domain structure in YAML (topology, retry settings, etc.) but need to +set some properties at runtime — for example, loading bootstrap servers or credentials from a secrets manager. + +Declare your domains in `application.yaml` as usual, then define a `KafkaPropsCustomizer` bean to override specific +properties after the YAML is loaded. The customizer receives the full map of configured domains and can modify +any property on any domain. + +:::caution[YAML domains are optional] +The `KafkaPropsCustomizer` can work with or without pre-existing YAML domains. If no domains are defined in your +`application.yaml` under `reactive.commons.kafka`, you can define all domains directly inside the customizer using +`domainProperties.put("", AsyncKafkaProps.builder()...build())`. At least one domain must exist after the +customizer +executes, otherwise an `InvalidConfigurationException` is thrown. +::: + +You have two options: + +**Option A: Define domains in YAML, then override with customizer** + +Declare your domains in `application.yaml` as usual, then use the customizer to override or extend them. + +```yaml title="application.yaml" +reactive: + commons: + kafka: + app: # first domain (will be treated as the default) + retryDelay: 60000 + maxRetries: 3 + accounts: # second domain with independent cluster + retryDelay: 40000 +``` ```java package sample; import org.reactivecommons.async.kafka.config.KafkaProperties; -import org.reactivecommons.async.kafka.config.props.AsyncProps; -import org.reactivecommons.async.kafka.config.props.AsyncKafkaPropsDomainProperties; +import org.reactivecommons.async.kafka.config.props.AsyncKafkaProps; +import org.reactivecommons.async.kafka.config.props.AsyncKafkaPropsDomain; import org.springframework.context.annotation.Bean; -import org.springframework.context.annotation.Primary; +import org.springframework.context.annotation.Configuration; @Configuration -public class MyDomainConfig { +public class KafkaConfig { + + // Loads Kafka connection properties from a secrets manager at runtime. + // See the "Loading properties from a secret" section below for a complete implementation example. + private KafkaProperties loadFromSecret(String secretName) { + // ... + return new KafkaProperties(); + } @Bean - @Primary - public AsyncKafkaPropsDomainProperties customKafkaDomainProperties() { - KafkaProperties propertiesApp = new KafkaProperties(); - propertiesApp.setBootstrapServers(List.of("localhost:9092")); - - KafkaProperties propertiesAccounts = new KafkaProperties(); - propertiesAccounts.setBootstrapServers(List.of("localhost:9093")); - - return AsyncKafkaPropsDomainProperties.builder() - .withDomain("app", AsyncProps.builder() - .connectionProperties(propertiesApp) - .build()) - .withDomain("accounts", AsyncProps.builder() - .connectionProperties(propertiesAccounts) - .build()) - .build(); + public AsyncKafkaPropsDomain.KafkaPropsCustomizer kafkaPropsCustomizer() { + return domainProperties -> { + // Customize the "app" domain — overrides take precedence over YAML values + AsyncKafkaProps app = domainProperties.get("app"); + if (app != null) { + app.setConnectionProperties(loadFromSecret("secret-app-kafka")); + } + + // Customize the "accounts" domain independently + AsyncKafkaProps accounts = domainProperties.get("accounts"); + if (accounts != null) { + accounts.setConnectionProperties(loadFromSecret("secret-accounts-kafka")); + } + }; } } ``` +**Option B: Define all domains in the customizer (no YAML domains)** + +If you prefer full programmatic control, **omit the `reactive.commons.kafka` section entirely from +your `application.yaml`** and define all domains +inside the customizer: + +```java +package sample; + +import org.reactivecommons.async.kafka.config.KafkaProperties; +import org.reactivecommons.async.kafka.config.props.AsyncKafkaProps; +import org.reactivecommons.async.kafka.config.props.AsyncKafkaPropsDomain; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; + +@Configuration +public class KafkaConfig { + + private KafkaProperties loadFromSecret(String secretName) { + // ... + return new KafkaProperties(); + } + + @Bean + public AsyncKafkaPropsDomain.KafkaPropsCustomizer kafkaPropsCustomizer() { + return domainProperties -> { + // Define all domains programmatically + domainProperties.put("app", AsyncKafkaProps.builder() + .retryDelay(60000) + .maxRetries(3) + .connectionProperties(loadFromSecret("secret-app-kafka")) + .build()); + + domainProperties.put("accounts", AsyncKafkaProps.builder() + .retryDelay(40000) + .connectionProperties(loadFromSecret("secret-accounts-kafka")) + .build()); + }; + } +} +``` + +**Key rules for the hybrid approach:** + +- Properties set in the customizer **take precedence** over YAML values. +- YAML values not touched by the customizer are **preserved**. +- The customizer can also **add new domains** by calling `domainProperties.put("newDomain", asyncKafkaProps)`. +- The first domain declared in YAML becomes the **default domain** and automatically resolves handlers registered + without an explicit domain (e.g., via `HandlerRegistry.register().listenEvent(...)`). + ## Loading properties from a secret -Additionally, if you want to set only connection properties you can use the `AsyncKafkaPropsDomain.KafkaSecretFiller` -class. +:::danger[Deprecated] +Using `AsyncKafkaPropsDomain.KafkaSecretFiller` to load secrets is **deprecated** and will be removed in a future +version. Use **[Approach 2: Hybrid YAML + `KafkaPropsCustomizer`](#approach-2-hybrid-yaml--kafkapropscustomizer)** +instead, which provides full control over all domain properties at runtime and is the recommended way to integrate with +a secrets manager. +::: + +The recommended way to load connection properties from a secrets manager is to use the `KafkaPropsCustomizer` (see +[Approach 2](#approach-2-hybrid-yaml--kafkapropscustomizer)). This gives you full control over all domain properties +at runtime. The example below uses the [Secrets Manager](https://github.com/bancolombia/secrets-manager) library. + +1. Create a `@ConfigurationProperties` record to map the secret fields: + +```java +import org.springframework.boot.context.properties.ConfigurationProperties; + +@ConfigurationProperties(prefix = "helpers.secrets-manager") +public record SecretsManagerProperties( + String endpoint, + Integer cacheSize, + Integer cacheTime, + String kafka) { +} +``` + +2. Create a `KafkaConnectionProperties` record to map the fields of your secret and provide a conversion method: ```java +import org.reactivecommons.async.kafka.config.KafkaProperties; -@Bean -@Primary -public AsyncKafkaPropsDomain.KafkaSecretFiller customKafkaFiller() { - return (domain, asyncProps) -> { - // customize asyncProps here by domain - }; +import java.util.List; + +public record KafkaConnectionProperties(String bootstrapServers) { + + public KafkaProperties toKafkaProperties() { + var kafkaProperties = new KafkaProperties(); + kafkaProperties.setBootstrapServers(List.of(this.bootstrapServers().split(","))); + return kafkaProperties; + } +} +``` + +3. Create a `SecretsConfig` class that registers the `GenericManager` bean and exposes the Kafka secret as a bean: + +```java +import co.com.bancolombia.secretsmanager.api.GenericManager; +import co.com.bancolombia.secretsmanager.connector.AWSSecretManagerConnector; +import lombok.RequiredArgsConstructor; +import lombok.extern.log4j.Log4j2; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.context.annotation.Profile; +import software.amazon.awssdk.regions.Region; + +@Log4j2 +@Configuration +@RequiredArgsConstructor +public class SecretsConfig { + + private final SecretsManagerProperties properties; + private static final String REGION_SECRET = Region.US_EAST_1.toString(); + + @Bean + @Profile("!local") + public GenericManager connectionAws() { + return new AWSSecretManagerConnector(REGION_SECRET); + } + + @Bean + @Profile("local") + public GenericManager connectionLocal() { + return new AWSSecretManagerConnector(REGION_SECRET, properties.endpoint()); + } + + public T getSecret(String secretName, Class cls, GenericManager connector) { + try { + log.info("Secret was obtained successfully"); + return connector.getSecret(secretName, cls); + } catch (Exception e) { + log.error("Error getting secret: {}", e.getMessage()); + return null; + } + } + + @Bean + public KafkaConnectionProperties getSecretKafka(GenericManager connector) { + return this.getSecret(properties.kafka(), KafkaConnectionProperties.class, connector); + } +} +``` + +4. Create a separate `KafkaConfig` class that injects the `KafkaConnectionProperties` bean and defines the + `KafkaPropsCustomizer`: + +```java +import lombok.RequiredArgsConstructor; +import org.reactivecommons.async.kafka.config.props.AsyncKafkaProps; +import org.reactivecommons.async.kafka.config.props.AsyncKafkaPropsDomain; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; + +@Configuration +@RequiredArgsConstructor +public class KafkaConfig { + + private final KafkaConnectionProperties kafkaConnectionProperties; + + @Bean + public AsyncKafkaPropsDomain.KafkaPropsCustomizer kafkaPropsCustomizer() { + return domainProperties -> { + AsyncKafkaProps app = domainProperties.get("app"); + if (app != null) { + app.setConnectionProperties(kafkaConnectionProperties.toKafkaProperties()); + } + }; + } } ``` diff --git a/docs/docusaurus.config.js b/docs/docusaurus.config.js index 76ce0a31..0ed98258 100644 --- a/docs/docusaurus.config.js +++ b/docs/docusaurus.config.js @@ -24,7 +24,12 @@ const config = { projectName: 'reactive-commons-java', // Usually your repo name. onBrokenLinks: 'throw', - onBrokenMarkdownLinks: 'warn', + markdown: { + hooks: { + onBrokenMarkdownLinks: 'warn', + onBrokenMarkdownImages: 'throw', + }, + }, // Even if you don't use internationalization, you can use this field to set // useful metadata like html lang. For example, if your site is Chinese, you @@ -44,7 +49,7 @@ const config = { // Please change this to your repo. // Remove this to remove the "edit this page" links. editUrl: - 'https://github.com/reactive-commons/reactive-commons-java/tree/docs/docs', + 'https://github.com/reactive-commons/reactive-commons-java/tree/docs/docs', }, theme: { customCss: './src/css/custom.css', diff --git a/docs/package-lock.json b/docs/package-lock.json index b4cc6652..66af1725 100644 --- a/docs/package-lock.json +++ b/docs/package-lock.json @@ -8,64 +8,64 @@ "name": "docs", "version": "0.0.0", "dependencies": { - "@docusaurus/core": "^3.9.2", - "@docusaurus/preset-classic": "^3.9.2", - "@docusaurus/theme-common": "^3.9.2", + "@docusaurus/core": "^3.10.1", + "@docusaurus/preset-classic": "^3.10.1", + "@docusaurus/theme-common": "^3.10.1", "@mdx-js/react": "^3.1.1", "clsx": "^2.1.1", "prism-react-renderer": "^2.4.1", - "react": "^19.2.4", - "react-dom": "^19.2.4" + "react": "^19.2.6", + "react-dom": "^19.2.6" }, "devDependencies": { - "@docusaurus/module-type-aliases": "^3.9.2", - "@docusaurus/types": "^3.9.2" + "@docusaurus/module-type-aliases": "^3.10.1", + "@docusaurus/types": "^3.10.1" }, "engines": { "node": ">=18.0" } }, "node_modules/@algolia/abtesting": { - "version": "1.15.1", - "resolved": "https://registry.npmjs.org/@algolia/abtesting/-/abtesting-1.15.1.tgz", - "integrity": "sha512-2yuIC48rUuHGhU1U5qJ9kJHaxYpJ0jpDHJVI5ekOxSMYXlH4+HP+pA31G820lsAznfmu2nzDV7n5RO44zIY1zw==", + "version": "1.18.1", + "resolved": "https://registry.npmjs.org/@algolia/abtesting/-/abtesting-1.18.1.tgz", + "integrity": "sha512-aehCadlWOGvrT91KUIZpC0MbB8KBW9yUuvTJFd2xesR7le/IsT4nJUnjCCZ4ZqZCeTcPHPV5mo//fZ5oxcSVYw==", "license": "MIT", "dependencies": { - "@algolia/client-common": "5.49.1", - "@algolia/requester-browser-xhr": "5.49.1", - "@algolia/requester-fetch": "5.49.1", - "@algolia/requester-node-http": "5.49.1" + "@algolia/client-common": "5.52.1", + "@algolia/requester-browser-xhr": "5.52.1", + "@algolia/requester-fetch": "5.52.1", + "@algolia/requester-node-http": "5.52.1" }, "engines": { "node": ">= 14.0.0" } }, "node_modules/@algolia/autocomplete-core": { - "version": "1.19.2", - "resolved": "https://registry.npmjs.org/@algolia/autocomplete-core/-/autocomplete-core-1.19.2.tgz", - "integrity": "sha512-mKv7RyuAzXvwmq+0XRK8HqZXt9iZ5Kkm2huLjgn5JoCPtDy+oh9yxUMfDDaVCw0oyzZ1isdJBc7l9nuCyyR7Nw==", + "version": "1.19.8", + "resolved": "https://registry.npmjs.org/@algolia/autocomplete-core/-/autocomplete-core-1.19.8.tgz", + "integrity": "sha512-3YEorYg44niXcm7gkft3nXYItHd44e8tmh4D33CTszPgP0QWkaLEaFywiNyJBo7UL/mqObA/G9RYuU7R8tN1IA==", "license": "MIT", "dependencies": { - "@algolia/autocomplete-plugin-algolia-insights": "1.19.2", - "@algolia/autocomplete-shared": "1.19.2" + "@algolia/autocomplete-plugin-algolia-insights": "1.19.8", + "@algolia/autocomplete-shared": "1.19.8" } }, "node_modules/@algolia/autocomplete-plugin-algolia-insights": { - "version": "1.19.2", - "resolved": "https://registry.npmjs.org/@algolia/autocomplete-plugin-algolia-insights/-/autocomplete-plugin-algolia-insights-1.19.2.tgz", - "integrity": "sha512-TjxbcC/r4vwmnZaPwrHtkXNeqvlpdyR+oR9Wi2XyfORkiGkLTVhX2j+O9SaCCINbKoDfc+c2PB8NjfOnz7+oKg==", + "version": "1.19.8", + "resolved": "https://registry.npmjs.org/@algolia/autocomplete-plugin-algolia-insights/-/autocomplete-plugin-algolia-insights-1.19.8.tgz", + "integrity": "sha512-ZvJWO8ZZJDpc1LNM2TTBdmQsZBLMR4rU5iNR2OYvEeFBiaf/0ESnRSSLQbryarJY4SVxtoz6A2ZtDMNM+iQEAA==", "license": "MIT", "dependencies": { - "@algolia/autocomplete-shared": "1.19.2" + "@algolia/autocomplete-shared": "1.19.8" }, "peerDependencies": { "search-insights": ">= 1 < 3" } }, "node_modules/@algolia/autocomplete-shared": { - "version": "1.19.2", - "resolved": "https://registry.npmjs.org/@algolia/autocomplete-shared/-/autocomplete-shared-1.19.2.tgz", - "integrity": "sha512-jEazxZTVD2nLrC+wYlVHQgpBoBB5KPStrJxLzsIFl6Kqd1AlG9sIAGl39V5tECLpIQzB3Qa2T6ZPJ1ChkwMK/w==", + "version": "1.19.8", + "resolved": "https://registry.npmjs.org/@algolia/autocomplete-shared/-/autocomplete-shared-1.19.8.tgz", + "integrity": "sha512-h5hf2t8ejF6vlOgvLaZzQbWs5SyH2z4PAWygNAvvD/2RI29hdQ54ldUGwqVuj9Srs+n8XUKTPUqb7fvhBhQrnQ==", "license": "MIT", "peerDependencies": { "@algolia/client-search": ">= 4.9.1 < 6", @@ -73,100 +73,99 @@ } }, "node_modules/@algolia/client-abtesting": { - "version": "5.49.1", - "resolved": "https://registry.npmjs.org/@algolia/client-abtesting/-/client-abtesting-5.49.1.tgz", - "integrity": "sha512-h6M7HzPin+45/l09q0r2dYmocSSt2MMGOOk5c4O5K/bBBlEwf1BKfN6z+iX4b8WXcQQhf7rgQwC52kBZJt/ZZw==", + "version": "5.52.1", + "resolved": "https://registry.npmjs.org/@algolia/client-abtesting/-/client-abtesting-5.52.1.tgz", + "integrity": "sha512-HmXOGBOAOJPounpBzBpuY0zDYeiCpxgHnQmuA7JO6ScukcBdGp3/XM9zJk5pJx/xNGD68mbPGXWpDxGtl6BwDQ==", "license": "MIT", "dependencies": { - "@algolia/client-common": "5.49.1", - "@algolia/requester-browser-xhr": "5.49.1", - "@algolia/requester-fetch": "5.49.1", - "@algolia/requester-node-http": "5.49.1" + "@algolia/client-common": "5.52.1", + "@algolia/requester-browser-xhr": "5.52.1", + "@algolia/requester-fetch": "5.52.1", + "@algolia/requester-node-http": "5.52.1" }, "engines": { "node": ">= 14.0.0" } }, "node_modules/@algolia/client-analytics": { - "version": "5.49.1", - "resolved": "https://registry.npmjs.org/@algolia/client-analytics/-/client-analytics-5.49.1.tgz", - "integrity": "sha512-048T9/Z8OeLmTk8h76QUqaNFp7Rq2VgS2Zm6Y2tNMYGQ1uNuzePY/udB5l5krlXll7ZGflyCjFvRiOtlPZpE9g==", + "version": "5.52.1", + "resolved": "https://registry.npmjs.org/@algolia/client-analytics/-/client-analytics-5.52.1.tgz", + "integrity": "sha512-5oo4+I8iixie9vXhCyNFCzeIr8pqA3FQ//VsLHTDvZAV4ttYOPGvYHGQq5NSalrLx5Jc3dRro/5uDOlnUMcBJg==", "license": "MIT", "dependencies": { - "@algolia/client-common": "5.49.1", - "@algolia/requester-browser-xhr": "5.49.1", - "@algolia/requester-fetch": "5.49.1", - "@algolia/requester-node-http": "5.49.1" + "@algolia/client-common": "5.52.1", + "@algolia/requester-browser-xhr": "5.52.1", + "@algolia/requester-fetch": "5.52.1", + "@algolia/requester-node-http": "5.52.1" }, "engines": { "node": ">= 14.0.0" } }, "node_modules/@algolia/client-common": { - "version": "5.49.1", - "resolved": "https://registry.npmjs.org/@algolia/client-common/-/client-common-5.49.1.tgz", - "integrity": "sha512-vp5/a9ikqvf3mn9QvHN8PRekn8hW34aV9eX+O0J5mKPZXeA6Pd5OQEh2ZWf7gJY6yyfTlLp5LMFzQUAU+Fpqpg==", + "version": "5.52.1", + "resolved": "https://registry.npmjs.org/@algolia/client-common/-/client-common-5.52.1.tgz", + "integrity": "sha512-qCDoZfx5MpX7XQzvQ3bC4tSEMkQWQMaF/ABtLuoze03Y/flR563CCSws02qIJ23oX7lxl92LsilZjINVyTdtLw==", "license": "MIT", "engines": { "node": ">= 14.0.0" } }, "node_modules/@algolia/client-insights": { - "version": "5.49.1", - "resolved": "https://registry.npmjs.org/@algolia/client-insights/-/client-insights-5.49.1.tgz", - "integrity": "sha512-B6N7PgkvYrul3bntTz/l6uXnhQ2bvP+M7NqTcayh681tSqPaA5cJCUBp/vrP7vpPRpej4Eeyx2qz5p0tE/2N2g==", + "version": "5.52.1", + "resolved": "https://registry.npmjs.org/@algolia/client-insights/-/client-insights-5.52.1.tgz", + "integrity": "sha512-hnGs0/lsFJ2PWDxNBz7pxreXo/Xz7gxYRcfePBUjsH26ad0kU/sgnVZd9LwWBpsQv65z2jlb5dkyaB9WE9M9FQ==", "license": "MIT", "dependencies": { - "@algolia/client-common": "5.49.1", - "@algolia/requester-browser-xhr": "5.49.1", - "@algolia/requester-fetch": "5.49.1", - "@algolia/requester-node-http": "5.49.1" + "@algolia/client-common": "5.52.1", + "@algolia/requester-browser-xhr": "5.52.1", + "@algolia/requester-fetch": "5.52.1", + "@algolia/requester-node-http": "5.52.1" }, "engines": { "node": ">= 14.0.0" } }, "node_modules/@algolia/client-personalization": { - "version": "5.49.1", - "resolved": "https://registry.npmjs.org/@algolia/client-personalization/-/client-personalization-5.49.1.tgz", - "integrity": "sha512-v+4DN+lkYfBd01Hbnb9ZrCHe7l+mvihyx218INRX/kaCXROIWUDIT1cs3urQxfE7kXBFnLsqYeOflQALv/gA5w==", + "version": "5.52.1", + "resolved": "https://registry.npmjs.org/@algolia/client-personalization/-/client-personalization-5.52.1.tgz", + "integrity": "sha512-2VxxNc/uBysyKvGeBdSM5n9eIDKH8kWD7wd9/yqbJAiVwU4Yv6tU1LSJusHKrXV/aCu1KW7t9Gug9QyeEmtn/Q==", "license": "MIT", "dependencies": { - "@algolia/client-common": "5.49.1", - "@algolia/requester-browser-xhr": "5.49.1", - "@algolia/requester-fetch": "5.49.1", - "@algolia/requester-node-http": "5.49.1" + "@algolia/client-common": "5.52.1", + "@algolia/requester-browser-xhr": "5.52.1", + "@algolia/requester-fetch": "5.52.1", + "@algolia/requester-node-http": "5.52.1" }, "engines": { "node": ">= 14.0.0" } }, "node_modules/@algolia/client-query-suggestions": { - "version": "5.49.1", - "resolved": "https://registry.npmjs.org/@algolia/client-query-suggestions/-/client-query-suggestions-5.49.1.tgz", - "integrity": "sha512-Un11cab6ZCv0W+Jiak8UktGIqoa4+gSNgEZNfG8m8eTsXGqwIEr370H3Rqwj87zeNSlFpH2BslMXJ/cLNS1qtg==", + "version": "5.52.1", + "resolved": "https://registry.npmjs.org/@algolia/client-query-suggestions/-/client-query-suggestions-5.52.1.tgz", + "integrity": "sha512-O6mPtsw3xEfNOe6gWFpYLeAZAIljNa4Hgna3bq15PwyN7nbjTY0wXJFRbzs/0YVf75Br+SbOQUmjKxXYjDiSiQ==", "license": "MIT", "dependencies": { - "@algolia/client-common": "5.49.1", - "@algolia/requester-browser-xhr": "5.49.1", - "@algolia/requester-fetch": "5.49.1", - "@algolia/requester-node-http": "5.49.1" + "@algolia/client-common": "5.52.1", + "@algolia/requester-browser-xhr": "5.52.1", + "@algolia/requester-fetch": "5.52.1", + "@algolia/requester-node-http": "5.52.1" }, "engines": { "node": ">= 14.0.0" } }, "node_modules/@algolia/client-search": { - "version": "5.49.1", - "resolved": "https://registry.npmjs.org/@algolia/client-search/-/client-search-5.49.1.tgz", - "integrity": "sha512-Nt9hri7nbOo0RipAsGjIssHkpLMHHN/P7QqENywAq5TLsoYDzUyJGny8FEiD/9KJUxtGH8blGpMedilI6kK3rA==", + "version": "5.52.1", + "resolved": "https://registry.npmjs.org/@algolia/client-search/-/client-search-5.52.1.tgz", + "integrity": "sha512-gA8oJOV1LnQQkDf91iebNnFInHuW0gRPEgLSOQ7EfipCEjYTHm5swm1DlH9H5RaRw4RrHuzHBegnlzc0MAstcg==", "license": "MIT", - "peer": true, "dependencies": { - "@algolia/client-common": "5.49.1", - "@algolia/requester-browser-xhr": "5.49.1", - "@algolia/requester-fetch": "5.49.1", - "@algolia/requester-node-http": "5.49.1" + "@algolia/client-common": "5.52.1", + "@algolia/requester-browser-xhr": "5.52.1", + "@algolia/requester-fetch": "5.52.1", + "@algolia/requester-node-http": "5.52.1" }, "engines": { "node": ">= 14.0.0" @@ -179,81 +178,81 @@ "license": "MIT" }, "node_modules/@algolia/ingestion": { - "version": "1.49.1", - "resolved": "https://registry.npmjs.org/@algolia/ingestion/-/ingestion-1.49.1.tgz", - "integrity": "sha512-b5hUXwDqje0Y4CpU6VL481DXgPgxpTD5sYMnfQTHKgUispGnaCLCm2/T9WbJo1YNUbX3iHtYDArp804eD6CmRQ==", + "version": "1.52.1", + "resolved": "https://registry.npmjs.org/@algolia/ingestion/-/ingestion-1.52.1.tgz", + "integrity": "sha512-U9zZfc5xIu9wRxZkt+HceJUAD4VKHKbAyLSloJdEyMRmphXeibfrY9cxqIXBcmPeZzGhn3Imb35Dq8l19PkJhw==", "license": "MIT", "dependencies": { - "@algolia/client-common": "5.49.1", - "@algolia/requester-browser-xhr": "5.49.1", - "@algolia/requester-fetch": "5.49.1", - "@algolia/requester-node-http": "5.49.1" + "@algolia/client-common": "5.52.1", + "@algolia/requester-browser-xhr": "5.52.1", + "@algolia/requester-fetch": "5.52.1", + "@algolia/requester-node-http": "5.52.1" }, "engines": { "node": ">= 14.0.0" } }, "node_modules/@algolia/monitoring": { - "version": "1.49.1", - "resolved": "https://registry.npmjs.org/@algolia/monitoring/-/monitoring-1.49.1.tgz", - "integrity": "sha512-bvrXwZ0WsL3rN6Q4m4QqxsXFCo6WAew7sAdrpMQMK4Efn4/W920r9ptOuckejOSSvyLr9pAWgC5rsHhR2FYuYw==", + "version": "1.52.1", + "resolved": "https://registry.npmjs.org/@algolia/monitoring/-/monitoring-1.52.1.tgz", + "integrity": "sha512-a3SGNceHmkQfq77iG8Ka+w1pvwfZa/0lzEIgse30fL0kD+yKnd/dg0dQvSfFPAEt2f21DMcGkDSSeJlO3KdQjQ==", "license": "MIT", "dependencies": { - "@algolia/client-common": "5.49.1", - "@algolia/requester-browser-xhr": "5.49.1", - "@algolia/requester-fetch": "5.49.1", - "@algolia/requester-node-http": "5.49.1" + "@algolia/client-common": "5.52.1", + "@algolia/requester-browser-xhr": "5.52.1", + "@algolia/requester-fetch": "5.52.1", + "@algolia/requester-node-http": "5.52.1" }, "engines": { "node": ">= 14.0.0" } }, "node_modules/@algolia/recommend": { - "version": "5.49.1", - "resolved": "https://registry.npmjs.org/@algolia/recommend/-/recommend-5.49.1.tgz", - "integrity": "sha512-h2yz3AGeGkQwNgbLmoe3bxYs8fac4An1CprKTypYyTU/k3Q+9FbIvJ8aS1DoBKaTjSRZVoyQS7SZQio6GaHbZw==", + "version": "5.52.1", + "resolved": "https://registry.npmjs.org/@algolia/recommend/-/recommend-5.52.1.tgz", + "integrity": "sha512-z98QEguCFDpxb4S/PyrUK1igqF8tPsdbqOUUO6ON91vJ58w+Gwa6ncrI0oNXSFcrkxA5EqPKPQ2A1PBCn08TYQ==", "license": "MIT", "dependencies": { - "@algolia/client-common": "5.49.1", - "@algolia/requester-browser-xhr": "5.49.1", - "@algolia/requester-fetch": "5.49.1", - "@algolia/requester-node-http": "5.49.1" + "@algolia/client-common": "5.52.1", + "@algolia/requester-browser-xhr": "5.52.1", + "@algolia/requester-fetch": "5.52.1", + "@algolia/requester-node-http": "5.52.1" }, "engines": { "node": ">= 14.0.0" } }, "node_modules/@algolia/requester-browser-xhr": { - "version": "5.49.1", - "resolved": "https://registry.npmjs.org/@algolia/requester-browser-xhr/-/requester-browser-xhr-5.49.1.tgz", - "integrity": "sha512-2UPyRuUR/qpqSqH8mxFV5uBZWEpxhGPHLlx9Xf6OVxr79XO2ctzZQAhsmTZ6X22x+N8MBWpB9UEky7YU2HGFgA==", + "version": "5.52.1", + "resolved": "https://registry.npmjs.org/@algolia/requester-browser-xhr/-/requester-browser-xhr-5.52.1.tgz", + "integrity": "sha512-CI7+/0I11QeZM59Uc8whd2or0kqzFVjpaPn9Qpwll/krHcBAxk24WkAQ6WX+IwDVMfpont4YGbKwAmCre3vE8Q==", "license": "MIT", "dependencies": { - "@algolia/client-common": "5.49.1" + "@algolia/client-common": "5.52.1" }, "engines": { "node": ">= 14.0.0" } }, "node_modules/@algolia/requester-fetch": { - "version": "5.49.1", - "resolved": "https://registry.npmjs.org/@algolia/requester-fetch/-/requester-fetch-5.49.1.tgz", - "integrity": "sha512-N+xlE4lN+wpuT+4vhNEwPVlrfN+DWAZmSX9SYhbz986Oq8AMsqdntOqUyiOXVxYsQtfLwmiej24vbvJGYv1Qtw==", + "version": "5.52.1", + "resolved": "https://registry.npmjs.org/@algolia/requester-fetch/-/requester-fetch-5.52.1.tgz", + "integrity": "sha512-S6bDuw9byfOvm3T71cgdoZgrgnZq6hpdMLkx52Louh57nUAmvGQESz2aojOynQHjbTiV55smvAFbgn0qT4tJrg==", "license": "MIT", "dependencies": { - "@algolia/client-common": "5.49.1" + "@algolia/client-common": "5.52.1" }, "engines": { "node": ">= 14.0.0" } }, "node_modules/@algolia/requester-node-http": { - "version": "5.49.1", - "resolved": "https://registry.npmjs.org/@algolia/requester-node-http/-/requester-node-http-5.49.1.tgz", - "integrity": "sha512-zA5bkUOB5PPtTr182DJmajCiizHp0rCJQ0Chf96zNFvkdESKYlDeYA3tQ7r2oyHbu/8DiohAQ5PZ85edctzbXA==", + "version": "5.52.1", + "resolved": "https://registry.npmjs.org/@algolia/requester-node-http/-/requester-node-http-5.52.1.tgz", + "integrity": "sha512-tqZXM+54rWo4mk5jL5Z/flE11nPmNEdXwFBM5py9DkOmbjeCNemfVd45FyM97XdzfZ0dl9uOJC6PYn1FpkeyQg==", "license": "MIT", "dependencies": { - "@algolia/client-common": "5.49.1" + "@algolia/client-common": "5.52.1" }, "engines": { "node": ">= 14.0.0" @@ -274,9 +273,9 @@ } }, "node_modules/@babel/compat-data": { - "version": "7.29.0", - "resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.29.0.tgz", - "integrity": "sha512-T1NCJqT/j9+cn8fvkt7jtwbLBfLC/1y1c7NtCeXFRgzGTsafi68MRv8yzkYSapBnFA6L3U2VSc02ciDzoAJhJg==", + "version": "7.29.3", + "resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.29.3.tgz", + "integrity": "sha512-LIVqM46zQWZhj17qA8wb4nW/ixr2y1Nw+r1etiAWgRM6U1IqP+LNhL1yg440jYZR72jCWcWbLWzIosH+uP1fqg==", "license": "MIT", "engines": { "node": ">=6.9.0" @@ -287,7 +286,6 @@ "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.29.0.tgz", "integrity": "sha512-CGOfOJqWjg2qW/Mb6zNsDm+u5vFQ8DxXfbM09z69p5Z6+mE1ikP2jUXw+j42Pf1XTYED2Rni5f95npYeuwMDQA==", "license": "MIT", - "peer": true, "dependencies": { "@babel/code-frame": "^7.29.0", "@babel/generator": "^7.29.0", @@ -376,9 +374,9 @@ } }, "node_modules/@babel/helper-create-class-features-plugin": { - "version": "7.28.6", - "resolved": "https://registry.npmjs.org/@babel/helper-create-class-features-plugin/-/helper-create-class-features-plugin-7.28.6.tgz", - "integrity": "sha512-dTOdvsjnG3xNT9Y0AUg1wAl38y+4Rl4sf9caSQZOXdNqVn+H+HbbJ4IyyHaIqNR6SW9oJpA/RuRjsjCw2IdIow==", + "version": "7.29.3", + "resolved": "https://registry.npmjs.org/@babel/helper-create-class-features-plugin/-/helper-create-class-features-plugin-7.29.3.tgz", + "integrity": "sha512-RpLYy2sb51oNLjuu1iD3bwBqCBWUzjO0ocp+iaCP/lJtb2CPLcnC2Fftw+4sAzaMELGeWTgExSKADbdo0GFVzA==", "license": "MIT", "dependencies": { "@babel/helper-annotate-as-pure": "^7.27.3", @@ -386,7 +384,7 @@ "@babel/helper-optimise-call-expression": "^7.27.1", "@babel/helper-replace-supers": "^7.28.6", "@babel/helper-skip-transparent-expression-wrappers": "^7.27.1", - "@babel/traverse": "^7.28.6", + "@babel/traverse": "^7.29.0", "semver": "^6.3.1" }, "engines": { @@ -432,9 +430,9 @@ } }, "node_modules/@babel/helper-define-polyfill-provider": { - "version": "0.6.6", - "resolved": "https://registry.npmjs.org/@babel/helper-define-polyfill-provider/-/helper-define-polyfill-provider-0.6.6.tgz", - "integrity": "sha512-mOAsxeeKkUKayvZR3HeTYD/fICpCPLJrU5ZjelT/PA6WHtNDBOE436YiaEUvHN454bRM3CebhDsIpieCc4texA==", + "version": "0.6.8", + "resolved": "https://registry.npmjs.org/@babel/helper-define-polyfill-provider/-/helper-define-polyfill-provider-0.6.8.tgz", + "integrity": "sha512-47UwBLPpQi1NoWzLuHNjRoHlYXMwIJoBf7MFou6viC/sIHWYygpvr0B6IAyh5sBdA2nr2LPIRww8lfaUVQINBA==", "license": "MIT", "dependencies": { "@babel/helper-compilation-targets": "^7.28.6", @@ -609,22 +607,22 @@ } }, "node_modules/@babel/helpers": { - "version": "7.28.6", - "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.28.6.tgz", - "integrity": "sha512-xOBvwq86HHdB7WUDTfKfT/Vuxh7gElQ+Sfti2Cy6yIWNW05P8iUslOVcZ4/sKbE+/jQaukQAdz/gf3724kYdqw==", + "version": "7.29.2", + "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.29.2.tgz", + "integrity": "sha512-HoGuUs4sCZNezVEKdVcwqmZN8GoHirLUcLaYVNBK2J0DadGtdcqgr3BCbvH8+XUo4NGjNl3VOtSjEKNzqfFgKw==", "license": "MIT", "dependencies": { "@babel/template": "^7.28.6", - "@babel/types": "^7.28.6" + "@babel/types": "^7.29.0" }, "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/parser": { - "version": "7.29.0", - "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.29.0.tgz", - "integrity": "sha512-IyDgFV5GeDUVX4YdF/3CPULtVGSXXMLh1xVIgdCgxApktqnQV0r7/8Nqthg+8YLGaAtdyIlo2qIdZrbCv4+7ww==", + "version": "7.29.3", + "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.29.3.tgz", + "integrity": "sha512-b3ctpQwp+PROvU/cttc4OYl4MzfJUWy6FZg+PMXfzmt/+39iHVF0sDfqay8TQM3JA2EUOyKcFZt75jWriQijsA==", "license": "MIT", "dependencies": { "@babel/types": "^7.29.0" @@ -682,6 +680,22 @@ "@babel/core": "^7.0.0" } }, + "node_modules/@babel/plugin-bugfix-safari-rest-destructuring-rhs-array": { + "version": "7.29.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-bugfix-safari-rest-destructuring-rhs-array/-/plugin-bugfix-safari-rest-destructuring-rhs-array-7.29.3.tgz", + "integrity": "sha512-SRS46DFR4HqzUzCVgi90/xMoL+zeBDBvWdKYXSEzh79kXswNFEglUpMKxR04//dPqwYXWUBJ3mpUd933ru9Kmg==", + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.28.6", + "@babel/helper-skip-transparent-expression-wrappers": "^7.27.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" + } + }, "node_modules/@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining": { "version": "7.27.1", "resolved": "https://registry.npmjs.org/@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining/-/plugin-bugfix-v8-spread-parameters-in-optional-chaining-7.27.1.tgz", @@ -1212,9 +1226,9 @@ } }, "node_modules/@babel/plugin-transform-modules-systemjs": { - "version": "7.29.0", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-systemjs/-/plugin-transform-modules-systemjs-7.29.0.tgz", - "integrity": "sha512-PrujnVFbOdUpw4UHiVwKvKRLMMic8+eC0CuNlxjsyZUiBjhFdPsewdXCkveh2KqBA9/waD0W1b4hXSOBQJezpQ==", + "version": "7.29.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-systemjs/-/plugin-transform-modules-systemjs-7.29.4.tgz", + "integrity": "sha512-N7QmZ0xRZfjHOfZeQLJjwgX2zS9pdGHSVl/cjSGlo4dXMqvurfxXDMKY4RqEKzPozV78VMcd0lxyG13mlbKc4w==", "license": "MIT", "dependencies": { "@babel/helper-module-transforms": "^7.28.6", @@ -1749,18 +1763,19 @@ } }, "node_modules/@babel/preset-env": { - "version": "7.29.0", - "resolved": "https://registry.npmjs.org/@babel/preset-env/-/preset-env-7.29.0.tgz", - "integrity": "sha512-fNEdfc0yi16lt6IZo2Qxk3knHVdfMYX33czNb4v8yWhemoBhibCpQK/uYHtSKIiO+p/zd3+8fYVXhQdOVV608w==", + "version": "7.29.5", + "resolved": "https://registry.npmjs.org/@babel/preset-env/-/preset-env-7.29.5.tgz", + "integrity": "sha512-/69t2aEzGKHD76DyLbHysF/QH2LJOB8iFnYO37unDTKBTubzcMRv0f3H5EiN1Q6ajOd/eB7dAInF0qdFVS06kA==", "license": "MIT", "dependencies": { - "@babel/compat-data": "^7.29.0", + "@babel/compat-data": "^7.29.3", "@babel/helper-compilation-targets": "^7.28.6", "@babel/helper-plugin-utils": "^7.28.6", "@babel/helper-validator-option": "^7.27.1", "@babel/plugin-bugfix-firefox-class-in-computed-class-key": "^7.28.5", "@babel/plugin-bugfix-safari-class-field-initializer-scope": "^7.27.1", "@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression": "^7.27.1", + "@babel/plugin-bugfix-safari-rest-destructuring-rhs-array": "^7.29.3", "@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining": "^7.27.1", "@babel/plugin-bugfix-v8-static-class-fields-redefine-readonly": "^7.28.6", "@babel/plugin-proposal-private-property-in-object": "7.21.0-placeholder-for-preset-env.2", @@ -1792,7 +1807,7 @@ "@babel/plugin-transform-member-expression-literals": "^7.27.1", "@babel/plugin-transform-modules-amd": "^7.27.1", "@babel/plugin-transform-modules-commonjs": "^7.28.6", - "@babel/plugin-transform-modules-systemjs": "^7.29.0", + "@babel/plugin-transform-modules-systemjs": "^7.29.4", "@babel/plugin-transform-modules-umd": "^7.27.1", "@babel/plugin-transform-named-capturing-groups-regex": "^7.29.0", "@babel/plugin-transform-new-target": "^7.27.1", @@ -1833,12 +1848,12 @@ } }, "node_modules/@babel/preset-env/node_modules/babel-plugin-polyfill-corejs3": { - "version": "0.14.0", - "resolved": "https://registry.npmjs.org/babel-plugin-polyfill-corejs3/-/babel-plugin-polyfill-corejs3-0.14.0.tgz", - "integrity": "sha512-AvDcMxJ34W4Wgy4KBIIePQTAOP1Ie2WFwkQp3dB7FQ/f0lI5+nM96zUnYEOE1P9sEg0es5VCP0HxiWu5fUHZAQ==", + "version": "0.14.2", + "resolved": "https://registry.npmjs.org/babel-plugin-polyfill-corejs3/-/babel-plugin-polyfill-corejs3-0.14.2.tgz", + "integrity": "sha512-coWpDLJ410R781Npmn/SIBZEsAetR4xVi0SxLMXPaMO4lSf1MwnkGYMtkFxew0Dn8B3/CpbpYxN0JCgg8mn67g==", "license": "MIT", "dependencies": { - "@babel/helper-define-polyfill-provider": "^0.6.6", + "@babel/helper-define-polyfill-provider": "^0.6.8", "core-js-compat": "^3.48.0" }, "peerDependencies": { @@ -1916,18 +1931,6 @@ "node": ">=6.9.0" } }, - "node_modules/@babel/runtime-corejs3": { - "version": "7.29.0", - "resolved": "https://registry.npmjs.org/@babel/runtime-corejs3/-/runtime-corejs3-7.29.0.tgz", - "integrity": "sha512-TgUkdp71C9pIbBcHudc+gXZnihEDOjUAmXO1VO4HHGES7QLZcShR0stfKIxLSNIYx2fqhmJChOjm/wkF8wv4gA==", - "license": "MIT", - "dependencies": { - "core-js-pure": "^3.48.0" - }, - "engines": { - "node": ">=6.9.0" - } - }, "node_modules/@babel/template": { "version": "7.28.6", "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.28.6.tgz", @@ -2090,7 +2093,6 @@ } ], "license": "MIT", - "peer": true, "engines": { "node": ">=18" }, @@ -2113,7 +2115,6 @@ } ], "license": "MIT", - "peer": true, "engines": { "node": ">=18" } @@ -2223,7 +2224,6 @@ "resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-7.1.1.tgz", "integrity": "sha512-orRsuYpJVw8LdAwqqLykBj9ecS5/cRHlI5+nvTo8LcCKmzDmqVORXtOIYEEQuL9D4BxtA1lm5isAqzQZCoQ6Eg==", "license": "MIT", - "peer": true, "dependencies": { "cssesc": "^3.0.0", "util-deprecate": "^1.0.2" @@ -2645,7 +2645,6 @@ "resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-7.1.1.tgz", "integrity": "sha512-orRsuYpJVw8LdAwqqLykBj9ecS5/cRHlI5+nvTo8LcCKmzDmqVORXtOIYEEQuL9D4BxtA1lm5isAqzQZCoQ6Eg==", "license": "MIT", - "peer": true, "dependencies": { "cssesc": "^3.0.0", "util-deprecate": "^1.0.2" @@ -3313,9 +3312,9 @@ } }, "node_modules/@docsearch/core": { - "version": "4.6.0", - "resolved": "https://registry.npmjs.org/@docsearch/core/-/core-4.6.0.tgz", - "integrity": "sha512-IqG3oSd529jVRQ4dWZQKwZwQLVd//bWJTz2HiL0LkiHrI4U/vLrBasKB7lwQB/69nBAcCgs3TmudxTZSLH/ZQg==", + "version": "4.6.3", + "resolved": "https://registry.npmjs.org/@docsearch/core/-/core-4.6.3.tgz", + "integrity": "sha512-rUOujwIpxJRgD7+kicVsI3D5sqBvdiRTquzWBpTEXZs8ZXfGbfzpus5HqumaNYTppN2HvH8E2yNuRwYdHJeOlA==", "license": "MIT", "peerDependencies": { "@types/react": ">= 16.8.0 < 20.0.0", @@ -3335,20 +3334,20 @@ } }, "node_modules/@docsearch/css": { - "version": "4.6.0", - "resolved": "https://registry.npmjs.org/@docsearch/css/-/css-4.6.0.tgz", - "integrity": "sha512-YlcAimkXclvqta47g47efzCM5CFxDwv2ClkDfEs/fC/Ak0OxPH2b3czwa4o8O1TRBf+ujFF2RiUwszz2fPVNJQ==", + "version": "4.6.3", + "resolved": "https://registry.npmjs.org/@docsearch/css/-/css-4.6.3.tgz", + "integrity": "sha512-nlOwcXcsNAptQl4vlL4MA78qNJKO0Qlds5GuBjCoePgkebTXLSf8Qt1oyZ3YBshYupKXG9VRGEsk1zr23d+bzQ==", "license": "MIT" }, "node_modules/@docsearch/react": { - "version": "4.6.0", - "resolved": "https://registry.npmjs.org/@docsearch/react/-/react-4.6.0.tgz", - "integrity": "sha512-j8H5B4ArGxBPBWvw3X0J0Rm/Pjv2JDa2rV5OE0DLTp5oiBCptIJ/YlNOhZxuzbO2nwge+o3Z52nJRi3hryK9cA==", + "version": "4.6.3", + "resolved": "https://registry.npmjs.org/@docsearch/react/-/react-4.6.3.tgz", + "integrity": "sha512-Bg2wdDsoQVlNCcEKuEJAU04tvHCqgx8rIu+uIoM4pRtcx3TBKJuXutJik3LTA8LRc9YEyHkrYUrmcC0D7BYf+g==", "license": "MIT", "dependencies": { "@algolia/autocomplete-core": "1.19.2", - "@docsearch/core": "4.6.0", - "@docsearch/css": "4.6.0" + "@docsearch/core": "4.6.3", + "@docsearch/css": "4.6.3" }, "peerDependencies": { "@types/react": ">= 16.8.0 < 20.0.0", @@ -3371,10 +3370,42 @@ } } }, + "node_modules/@docsearch/react/node_modules/@algolia/autocomplete-core": { + "version": "1.19.2", + "resolved": "https://registry.npmjs.org/@algolia/autocomplete-core/-/autocomplete-core-1.19.2.tgz", + "integrity": "sha512-mKv7RyuAzXvwmq+0XRK8HqZXt9iZ5Kkm2huLjgn5JoCPtDy+oh9yxUMfDDaVCw0oyzZ1isdJBc7l9nuCyyR7Nw==", + "license": "MIT", + "dependencies": { + "@algolia/autocomplete-plugin-algolia-insights": "1.19.2", + "@algolia/autocomplete-shared": "1.19.2" + } + }, + "node_modules/@docsearch/react/node_modules/@algolia/autocomplete-plugin-algolia-insights": { + "version": "1.19.2", + "resolved": "https://registry.npmjs.org/@algolia/autocomplete-plugin-algolia-insights/-/autocomplete-plugin-algolia-insights-1.19.2.tgz", + "integrity": "sha512-TjxbcC/r4vwmnZaPwrHtkXNeqvlpdyR+oR9Wi2XyfORkiGkLTVhX2j+O9SaCCINbKoDfc+c2PB8NjfOnz7+oKg==", + "license": "MIT", + "dependencies": { + "@algolia/autocomplete-shared": "1.19.2" + }, + "peerDependencies": { + "search-insights": ">= 1 < 3" + } + }, + "node_modules/@docsearch/react/node_modules/@algolia/autocomplete-shared": { + "version": "1.19.2", + "resolved": "https://registry.npmjs.org/@algolia/autocomplete-shared/-/autocomplete-shared-1.19.2.tgz", + "integrity": "sha512-jEazxZTVD2nLrC+wYlVHQgpBoBB5KPStrJxLzsIFl6Kqd1AlG9sIAGl39V5tECLpIQzB3Qa2T6ZPJ1ChkwMK/w==", + "license": "MIT", + "peerDependencies": { + "@algolia/client-search": ">= 4.9.1 < 6", + "algoliasearch": ">= 4.9.1 < 6" + } + }, "node_modules/@docusaurus/babel": { - "version": "3.9.2", - "resolved": "https://registry.npmjs.org/@docusaurus/babel/-/babel-3.9.2.tgz", - "integrity": "sha512-GEANdi/SgER+L7Japs25YiGil/AUDnFFHaCGPBbundxoWtCkA2lmy7/tFmgED4y1htAy6Oi4wkJEQdGssnw9MA==", + "version": "3.10.1", + "resolved": "https://registry.npmjs.org/@docusaurus/babel/-/babel-3.10.1.tgz", + "integrity": "sha512-DZzFO1K3v/GoEt1fx1DiYHF4en+PuhtQf1AkQJa5zu3CoeKSpr5cpQRUlz3jr0m44wyzmSXu9bVpfir+N4+8bg==", "license": "MIT", "dependencies": { "@babel/core": "^7.25.9", @@ -3385,10 +3416,9 @@ "@babel/preset-react": "^7.25.9", "@babel/preset-typescript": "^7.25.9", "@babel/runtime": "^7.25.9", - "@babel/runtime-corejs3": "^7.25.9", "@babel/traverse": "^7.25.9", - "@docusaurus/logger": "3.9.2", - "@docusaurus/utils": "3.9.2", + "@docusaurus/logger": "3.10.1", + "@docusaurus/utils": "3.10.1", "babel-plugin-dynamic-import-node": "^2.3.3", "fs-extra": "^11.1.1", "tslib": "^2.6.0" @@ -3398,17 +3428,17 @@ } }, "node_modules/@docusaurus/bundler": { - "version": "3.9.2", - "resolved": "https://registry.npmjs.org/@docusaurus/bundler/-/bundler-3.9.2.tgz", - "integrity": "sha512-ZOVi6GYgTcsZcUzjblpzk3wH1Fya2VNpd5jtHoCCFcJlMQ1EYXZetfAnRHLcyiFeBABaI1ltTYbOBtH/gahGVA==", + "version": "3.10.1", + "resolved": "https://registry.npmjs.org/@docusaurus/bundler/-/bundler-3.10.1.tgz", + "integrity": "sha512-HIqQPvbqnnQRe4NsBd1774KRarjXqS6wHsWELtyuSs1gCfvixJO2jUGH/OEBtr1Gvzpw+ze5CjGMvSJ8UE1KUw==", "license": "MIT", "dependencies": { "@babel/core": "^7.25.9", - "@docusaurus/babel": "3.9.2", - "@docusaurus/cssnano-preset": "3.9.2", - "@docusaurus/logger": "3.9.2", - "@docusaurus/types": "3.9.2", - "@docusaurus/utils": "3.9.2", + "@docusaurus/babel": "3.10.1", + "@docusaurus/cssnano-preset": "3.10.1", + "@docusaurus/logger": "3.10.1", + "@docusaurus/types": "3.10.1", + "@docusaurus/utils": "3.10.1", "babel-loader": "^9.2.1", "clean-css": "^5.3.3", "copy-webpack-plugin": "^11.0.0", @@ -3426,7 +3456,7 @@ "tslib": "^2.6.0", "url-loader": "^4.1.1", "webpack": "^5.95.0", - "webpackbar": "^6.0.1" + "webpackbar": "^7.0.0" }, "engines": { "node": ">=20.0" @@ -3441,18 +3471,18 @@ } }, "node_modules/@docusaurus/core": { - "version": "3.9.2", - "resolved": "https://registry.npmjs.org/@docusaurus/core/-/core-3.9.2.tgz", - "integrity": "sha512-HbjwKeC+pHUFBfLMNzuSjqFE/58+rLVKmOU3lxQrpsxLBOGosYco/Q0GduBb0/jEMRiyEqjNT/01rRdOMWq5pw==", - "license": "MIT", - "dependencies": { - "@docusaurus/babel": "3.9.2", - "@docusaurus/bundler": "3.9.2", - "@docusaurus/logger": "3.9.2", - "@docusaurus/mdx-loader": "3.9.2", - "@docusaurus/utils": "3.9.2", - "@docusaurus/utils-common": "3.9.2", - "@docusaurus/utils-validation": "3.9.2", + "version": "3.10.1", + "resolved": "https://registry.npmjs.org/@docusaurus/core/-/core-3.10.1.tgz", + "integrity": "sha512-3pf2fXXw0eVk8WnC3T4LIigRDupcpvngpKo9Vy7mYyBhuddc0klDUuZAIfzMoK6z05pdlk6EFC/vBSX43+1O5w==", + "license": "MIT", + "dependencies": { + "@docusaurus/babel": "3.10.1", + "@docusaurus/bundler": "3.10.1", + "@docusaurus/logger": "3.10.1", + "@docusaurus/mdx-loader": "3.10.1", + "@docusaurus/utils": "3.10.1", + "@docusaurus/utils-common": "3.10.1", + "@docusaurus/utils-validation": "3.10.1", "boxen": "^6.2.1", "chalk": "^4.1.2", "chokidar": "^3.5.3", @@ -3464,7 +3494,7 @@ "escape-html": "^1.0.3", "eta": "^2.2.0", "eval": "^0.1.8", - "execa": "5.1.1", + "execa": "^5.1.1", "fs-extra": "^11.1.1", "html-tags": "^3.3.1", "html-webpack-plugin": "^5.6.0", @@ -3475,12 +3505,12 @@ "prompts": "^2.4.2", "react-helmet-async": "npm:@slorber/react-helmet-async@1.3.0", "react-loadable": "npm:@docusaurus/react-loadable@6.0.0", - "react-loadable-ssr-addon-v5-slorber": "^1.0.1", + "react-loadable-ssr-addon-v5-slorber": "^1.0.3", "react-router": "^5.3.4", "react-router-config": "^5.1.1", "react-router-dom": "^5.3.4", "semver": "^7.5.4", - "serve-handler": "^6.1.6", + "serve-handler": "^6.1.7", "tinypool": "^1.0.2", "tslib": "^2.6.0", "update-notifier": "^6.0.2", @@ -3496,15 +3526,21 @@ "node": ">=20.0" }, "peerDependencies": { + "@docusaurus/faster": "*", "@mdx-js/react": "^3.0.0", "react": "^18.0.0 || ^19.0.0", "react-dom": "^18.0.0 || ^19.0.0" + }, + "peerDependenciesMeta": { + "@docusaurus/faster": { + "optional": true + } } }, "node_modules/@docusaurus/cssnano-preset": { - "version": "3.9.2", - "resolved": "https://registry.npmjs.org/@docusaurus/cssnano-preset/-/cssnano-preset-3.9.2.tgz", - "integrity": "sha512-8gBKup94aGttRduABsj7bpPFTX7kbwu+xh3K9NMCF5K4bWBqTFYW+REKHF6iBVDHRJ4grZdIPbvkiHd/XNKRMQ==", + "version": "3.10.1", + "resolved": "https://registry.npmjs.org/@docusaurus/cssnano-preset/-/cssnano-preset-3.10.1.tgz", + "integrity": "sha512-eNfHGcTKCSq6xmcavAkX3RRclHaE2xRCMParlDXLdXVP01/a2e/jKXMj/0ULnLFQSNwwuI62L0Ge8J+nZsR7UQ==", "license": "MIT", "dependencies": { "cssnano-preset-advanced": "^6.1.2", @@ -3517,9 +3553,9 @@ } }, "node_modules/@docusaurus/logger": { - "version": "3.9.2", - "resolved": "https://registry.npmjs.org/@docusaurus/logger/-/logger-3.9.2.tgz", - "integrity": "sha512-/SVCc57ByARzGSU60c50rMyQlBuMIJCjcsJlkphxY6B0GV4UH3tcA1994N8fFfbJ9kX3jIBe/xg3XP5qBtGDbA==", + "version": "3.10.1", + "resolved": "https://registry.npmjs.org/@docusaurus/logger/-/logger-3.10.1.tgz", + "integrity": "sha512-oPjNFnfJsRCkePVjkGrxWGq4MvJKRQT0r9jOP0eRBTZ7Wr9FAbzdP/Gjs0I2Ss6YRkPoEgygKG112OkE6skvJw==", "license": "MIT", "dependencies": { "chalk": "^4.1.2", @@ -3530,14 +3566,14 @@ } }, "node_modules/@docusaurus/mdx-loader": { - "version": "3.9.2", - "resolved": "https://registry.npmjs.org/@docusaurus/mdx-loader/-/mdx-loader-3.9.2.tgz", - "integrity": "sha512-wiYoGwF9gdd6rev62xDU8AAM8JuLI/hlwOtCzMmYcspEkzecKrP8J8X+KpYnTlACBUUtXNJpSoCwFWJhLRevzQ==", + "version": "3.10.1", + "resolved": "https://registry.npmjs.org/@docusaurus/mdx-loader/-/mdx-loader-3.10.1.tgz", + "integrity": "sha512-GRmeb/wQ+iXRrFwcHBfgQhrJxGElgCsoTWZYDhccjsZVne1p8MK/EpQVIloXttz76TCe78kKD5AEG9n1xc1oxQ==", "license": "MIT", "dependencies": { - "@docusaurus/logger": "3.9.2", - "@docusaurus/utils": "3.9.2", - "@docusaurus/utils-validation": "3.9.2", + "@docusaurus/logger": "3.10.1", + "@docusaurus/utils": "3.10.1", + "@docusaurus/utils-validation": "3.10.1", "@mdx-js/mdx": "^3.0.0", "@slorber/remark-comment": "^1.0.0", "escape-html": "^1.0.3", @@ -3569,12 +3605,12 @@ } }, "node_modules/@docusaurus/module-type-aliases": { - "version": "3.9.2", - "resolved": "https://registry.npmjs.org/@docusaurus/module-type-aliases/-/module-type-aliases-3.9.2.tgz", - "integrity": "sha512-8qVe2QA9hVLzvnxP46ysuofJUIc/yYQ82tvA/rBTrnpXtCjNSFLxEZfd5U8cYZuJIVlkPxamsIgwd5tGZXfvew==", + "version": "3.10.1", + "resolved": "https://registry.npmjs.org/@docusaurus/module-type-aliases/-/module-type-aliases-3.10.1.tgz", + "integrity": "sha512-YoOZKUdGlp8xSYhuAkGdSo5Ydkbq4V4eK3sD8v0a2hloxCWdQbNBhkc+Ko9QyjpESc0BYcIGM5iHVAy5hdFV6w==", "license": "MIT", "dependencies": { - "@docusaurus/types": "3.9.2", + "@docusaurus/types": "3.10.1", "@types/history": "^4.7.11", "@types/react": "*", "@types/react-router-config": "*", @@ -3588,20 +3624,21 @@ } }, "node_modules/@docusaurus/plugin-content-blog": { - "version": "3.9.2", - "resolved": "https://registry.npmjs.org/@docusaurus/plugin-content-blog/-/plugin-content-blog-3.9.2.tgz", - "integrity": "sha512-3I2HXy3L1QcjLJLGAoTvoBnpOwa6DPUa3Q0dMK19UTY9mhPkKQg/DYhAGTiBUKcTR0f08iw7kLPqOhIgdV3eVQ==", - "license": "MIT", - "dependencies": { - "@docusaurus/core": "3.9.2", - "@docusaurus/logger": "3.9.2", - "@docusaurus/mdx-loader": "3.9.2", - "@docusaurus/theme-common": "3.9.2", - "@docusaurus/types": "3.9.2", - "@docusaurus/utils": "3.9.2", - "@docusaurus/utils-common": "3.9.2", - "@docusaurus/utils-validation": "3.9.2", + "version": "3.10.1", + "resolved": "https://registry.npmjs.org/@docusaurus/plugin-content-blog/-/plugin-content-blog-3.10.1.tgz", + "integrity": "sha512-mmkgE6Q2+K74tnkou7tXlpDLvoCU/qkSa2GSQ3XUiHWvcebCoDQzS670RR3tO8PmaWlIyWWISYWzZLuMfxunRA==", + "license": "MIT", + "dependencies": { + "@docusaurus/core": "3.10.1", + "@docusaurus/logger": "3.10.1", + "@docusaurus/mdx-loader": "3.10.1", + "@docusaurus/theme-common": "3.10.1", + "@docusaurus/types": "3.10.1", + "@docusaurus/utils": "3.10.1", + "@docusaurus/utils-common": "3.10.1", + "@docusaurus/utils-validation": "3.10.1", "cheerio": "1.0.0-rc.12", + "combine-promises": "^1.1.0", "feed": "^4.2.2", "fs-extra": "^11.1.1", "lodash": "^4.17.21", @@ -3622,21 +3659,20 @@ } }, "node_modules/@docusaurus/plugin-content-docs": { - "version": "3.9.2", - "resolved": "https://registry.npmjs.org/@docusaurus/plugin-content-docs/-/plugin-content-docs-3.9.2.tgz", - "integrity": "sha512-C5wZsGuKTY8jEYsqdxhhFOe1ZDjH0uIYJ9T/jebHwkyxqnr4wW0jTkB72OMqNjsoQRcb0JN3PcSeTwFlVgzCZg==", - "license": "MIT", - "peer": true, - "dependencies": { - "@docusaurus/core": "3.9.2", - "@docusaurus/logger": "3.9.2", - "@docusaurus/mdx-loader": "3.9.2", - "@docusaurus/module-type-aliases": "3.9.2", - "@docusaurus/theme-common": "3.9.2", - "@docusaurus/types": "3.9.2", - "@docusaurus/utils": "3.9.2", - "@docusaurus/utils-common": "3.9.2", - "@docusaurus/utils-validation": "3.9.2", + "version": "3.10.1", + "resolved": "https://registry.npmjs.org/@docusaurus/plugin-content-docs/-/plugin-content-docs-3.10.1.tgz", + "integrity": "sha512-2jRVrtzjf8LClGTHQlwlwuD3wQXRx3WEoF7XUarJ8Ou+0onV+SLtejsyfY9JLpfUh9hPhXM4pbBGkyAY4Bi3HQ==", + "license": "MIT", + "dependencies": { + "@docusaurus/core": "3.10.1", + "@docusaurus/logger": "3.10.1", + "@docusaurus/mdx-loader": "3.10.1", + "@docusaurus/module-type-aliases": "3.10.1", + "@docusaurus/theme-common": "3.10.1", + "@docusaurus/types": "3.10.1", + "@docusaurus/utils": "3.10.1", + "@docusaurus/utils-common": "3.10.1", + "@docusaurus/utils-validation": "3.10.1", "@types/react-router-config": "^5.0.7", "combine-promises": "^1.1.0", "fs-extra": "^11.1.1", @@ -3656,16 +3692,16 @@ } }, "node_modules/@docusaurus/plugin-content-pages": { - "version": "3.9.2", - "resolved": "https://registry.npmjs.org/@docusaurus/plugin-content-pages/-/plugin-content-pages-3.9.2.tgz", - "integrity": "sha512-s4849w/p4noXUrGpPUF0BPqIAfdAe76BLaRGAGKZ1gTDNiGxGcpsLcwJ9OTi1/V8A+AzvsmI9pkjie2zjIQZKA==", + "version": "3.10.1", + "resolved": "https://registry.npmjs.org/@docusaurus/plugin-content-pages/-/plugin-content-pages-3.10.1.tgz", + "integrity": "sha512-huJpaRPMl42nsFwuCXvV8bVDj2MazuwRJIUylI/RSlmZeJssVoZXeCjVf1y+1Drtpa9SKcdGn8yoJ76IRJijtw==", "license": "MIT", "dependencies": { - "@docusaurus/core": "3.9.2", - "@docusaurus/mdx-loader": "3.9.2", - "@docusaurus/types": "3.9.2", - "@docusaurus/utils": "3.9.2", - "@docusaurus/utils-validation": "3.9.2", + "@docusaurus/core": "3.10.1", + "@docusaurus/mdx-loader": "3.10.1", + "@docusaurus/types": "3.10.1", + "@docusaurus/utils": "3.10.1", + "@docusaurus/utils-validation": "3.10.1", "fs-extra": "^11.1.1", "tslib": "^2.6.0", "webpack": "^5.88.1" @@ -3679,15 +3715,15 @@ } }, "node_modules/@docusaurus/plugin-css-cascade-layers": { - "version": "3.9.2", - "resolved": "https://registry.npmjs.org/@docusaurus/plugin-css-cascade-layers/-/plugin-css-cascade-layers-3.9.2.tgz", - "integrity": "sha512-w1s3+Ss+eOQbscGM4cfIFBlVg/QKxyYgj26k5AnakuHkKxH6004ZtuLe5awMBotIYF2bbGDoDhpgQ4r/kcj4rQ==", + "version": "3.10.1", + "resolved": "https://registry.npmjs.org/@docusaurus/plugin-css-cascade-layers/-/plugin-css-cascade-layers-3.10.1.tgz", + "integrity": "sha512-r//fn+MNHkE1wCof8T29VAQezt1enGCpsFxoziBbvLgBM4JfXN2P3rxrBaavHmvLvm7lYkpJeitcDthwnmWCTw==", "license": "MIT", "dependencies": { - "@docusaurus/core": "3.9.2", - "@docusaurus/types": "3.9.2", - "@docusaurus/utils": "3.9.2", - "@docusaurus/utils-validation": "3.9.2", + "@docusaurus/core": "3.10.1", + "@docusaurus/types": "3.10.1", + "@docusaurus/utils": "3.10.1", + "@docusaurus/utils-validation": "3.10.1", "tslib": "^2.6.0" }, "engines": { @@ -3695,14 +3731,14 @@ } }, "node_modules/@docusaurus/plugin-debug": { - "version": "3.9.2", - "resolved": "https://registry.npmjs.org/@docusaurus/plugin-debug/-/plugin-debug-3.9.2.tgz", - "integrity": "sha512-j7a5hWuAFxyQAkilZwhsQ/b3T7FfHZ+0dub6j/GxKNFJp2h9qk/P1Bp7vrGASnvA9KNQBBL1ZXTe7jlh4VdPdA==", + "version": "3.10.1", + "resolved": "https://registry.npmjs.org/@docusaurus/plugin-debug/-/plugin-debug-3.10.1.tgz", + "integrity": "sha512-9KqOpKNfAyqGZykRb9LhIT/vyRF6sm/ykhjj/39JvaJahDS+jZJE0Z1Wfz9q3DUNDTMNN0Q7u/kk4rKKU+IJuA==", "license": "MIT", "dependencies": { - "@docusaurus/core": "3.9.2", - "@docusaurus/types": "3.9.2", - "@docusaurus/utils": "3.9.2", + "@docusaurus/core": "3.10.1", + "@docusaurus/types": "3.10.1", + "@docusaurus/utils": "3.10.1", "fs-extra": "^11.1.1", "react-json-view-lite": "^2.3.0", "tslib": "^2.6.0" @@ -3716,14 +3752,14 @@ } }, "node_modules/@docusaurus/plugin-google-analytics": { - "version": "3.9.2", - "resolved": "https://registry.npmjs.org/@docusaurus/plugin-google-analytics/-/plugin-google-analytics-3.9.2.tgz", - "integrity": "sha512-mAwwQJ1Us9jL/lVjXtErXto4p4/iaLlweC54yDUK1a97WfkC6Z2k5/769JsFgwOwOP+n5mUQGACXOEQ0XDuVUw==", + "version": "3.10.1", + "resolved": "https://registry.npmjs.org/@docusaurus/plugin-google-analytics/-/plugin-google-analytics-3.10.1.tgz", + "integrity": "sha512-8o0P1KtmgdYQHH+oInitPpRWI0Of5XednAX4+DMhQNSmGSRNrsEEHg1ebv35m9AgRClfAytCJ5jA9KvcASTyuA==", "license": "MIT", "dependencies": { - "@docusaurus/core": "3.9.2", - "@docusaurus/types": "3.9.2", - "@docusaurus/utils-validation": "3.9.2", + "@docusaurus/core": "3.10.1", + "@docusaurus/types": "3.10.1", + "@docusaurus/utils-validation": "3.10.1", "tslib": "^2.6.0" }, "engines": { @@ -3735,15 +3771,15 @@ } }, "node_modules/@docusaurus/plugin-google-gtag": { - "version": "3.9.2", - "resolved": "https://registry.npmjs.org/@docusaurus/plugin-google-gtag/-/plugin-google-gtag-3.9.2.tgz", - "integrity": "sha512-YJ4lDCphabBtw19ooSlc1MnxtYGpjFV9rEdzjLsUnBCeis2djUyCozZaFhCg6NGEwOn7HDDyMh0yzcdRpnuIvA==", + "version": "3.10.1", + "resolved": "https://registry.npmjs.org/@docusaurus/plugin-google-gtag/-/plugin-google-gtag-3.10.1.tgz", + "integrity": "sha512-pu3xIUo5o/zCMLfUY9BO5KOwSH0zIsAGyFRPvXHayFSA5XIhCU/SFuB0g0ZNjFn9niZLCaNvoeAuOGFJZq0fdw==", "license": "MIT", "dependencies": { - "@docusaurus/core": "3.9.2", - "@docusaurus/types": "3.9.2", - "@docusaurus/utils-validation": "3.9.2", - "@types/gtag.js": "^0.0.12", + "@docusaurus/core": "3.10.1", + "@docusaurus/types": "3.10.1", + "@docusaurus/utils-validation": "3.10.1", + "@types/gtag.js": "^0.0.20", "tslib": "^2.6.0" }, "engines": { @@ -3755,14 +3791,14 @@ } }, "node_modules/@docusaurus/plugin-google-tag-manager": { - "version": "3.9.2", - "resolved": "https://registry.npmjs.org/@docusaurus/plugin-google-tag-manager/-/plugin-google-tag-manager-3.9.2.tgz", - "integrity": "sha512-LJtIrkZN/tuHD8NqDAW1Tnw0ekOwRTfobWPsdO15YxcicBo2ykKF0/D6n0vVBfd3srwr9Z6rzrIWYrMzBGrvNw==", + "version": "3.10.1", + "resolved": "https://registry.npmjs.org/@docusaurus/plugin-google-tag-manager/-/plugin-google-tag-manager-3.10.1.tgz", + "integrity": "sha512-f6fyGHiCm7kJHBtAisGQS5oNBnpnMTYQZxDXeVrnw/3zWU+LMA22pr6UHGYkBKDbN+qPC5QHG3NuOfzQLq3+Lw==", "license": "MIT", "dependencies": { - "@docusaurus/core": "3.9.2", - "@docusaurus/types": "3.9.2", - "@docusaurus/utils-validation": "3.9.2", + "@docusaurus/core": "3.10.1", + "@docusaurus/types": "3.10.1", + "@docusaurus/utils-validation": "3.10.1", "tslib": "^2.6.0" }, "engines": { @@ -3774,17 +3810,17 @@ } }, "node_modules/@docusaurus/plugin-sitemap": { - "version": "3.9.2", - "resolved": "https://registry.npmjs.org/@docusaurus/plugin-sitemap/-/plugin-sitemap-3.9.2.tgz", - "integrity": "sha512-WLh7ymgDXjG8oPoM/T4/zUP7KcSuFYRZAUTl8vR6VzYkfc18GBM4xLhcT+AKOwun6kBivYKUJf+vlqYJkm+RHw==", + "version": "3.10.1", + "resolved": "https://registry.npmjs.org/@docusaurus/plugin-sitemap/-/plugin-sitemap-3.10.1.tgz", + "integrity": "sha512-C26MbmmqgdjkDq1htaZ3aD7LzEDKFWXfpyQpt0EOUThuq5nV77zDaedV20yHcVo9p+3ey9aZ4pbHA0D3QcZTzg==", "license": "MIT", "dependencies": { - "@docusaurus/core": "3.9.2", - "@docusaurus/logger": "3.9.2", - "@docusaurus/types": "3.9.2", - "@docusaurus/utils": "3.9.2", - "@docusaurus/utils-common": "3.9.2", - "@docusaurus/utils-validation": "3.9.2", + "@docusaurus/core": "3.10.1", + "@docusaurus/logger": "3.10.1", + "@docusaurus/types": "3.10.1", + "@docusaurus/utils": "3.10.1", + "@docusaurus/utils-common": "3.10.1", + "@docusaurus/utils-validation": "3.10.1", "fs-extra": "^11.1.1", "sitemap": "^7.1.1", "tslib": "^2.6.0" @@ -3798,15 +3834,15 @@ } }, "node_modules/@docusaurus/plugin-svgr": { - "version": "3.9.2", - "resolved": "https://registry.npmjs.org/@docusaurus/plugin-svgr/-/plugin-svgr-3.9.2.tgz", - "integrity": "sha512-n+1DE+5b3Lnf27TgVU5jM1d4x5tUh2oW5LTsBxJX4PsAPV0JGcmI6p3yLYtEY0LRVEIJh+8RsdQmRE66wSV8mw==", + "version": "3.10.1", + "resolved": "https://registry.npmjs.org/@docusaurus/plugin-svgr/-/plugin-svgr-3.10.1.tgz", + "integrity": "sha512-6SFxsmjWFkVLDmBUvFK6i72QjUwqyQFe4Ovz+SUJophJjOyVG3ZZG5IQpBC/kX/Gfv1yWeU9nWauH6F6Q7QX/Q==", "license": "MIT", "dependencies": { - "@docusaurus/core": "3.9.2", - "@docusaurus/types": "3.9.2", - "@docusaurus/utils": "3.9.2", - "@docusaurus/utils-validation": "3.9.2", + "@docusaurus/core": "3.10.1", + "@docusaurus/types": "3.10.1", + "@docusaurus/utils": "3.10.1", + "@docusaurus/utils-validation": "3.10.1", "@svgr/core": "8.1.0", "@svgr/webpack": "^8.1.0", "tslib": "^2.6.0", @@ -3821,26 +3857,26 @@ } }, "node_modules/@docusaurus/preset-classic": { - "version": "3.9.2", - "resolved": "https://registry.npmjs.org/@docusaurus/preset-classic/-/preset-classic-3.9.2.tgz", - "integrity": "sha512-IgyYO2Gvaigi21LuDIe+nvmN/dfGXAiMcV/murFqcpjnZc7jxFAxW+9LEjdPt61uZLxG4ByW/oUmX/DDK9t/8w==", - "license": "MIT", - "dependencies": { - "@docusaurus/core": "3.9.2", - "@docusaurus/plugin-content-blog": "3.9.2", - "@docusaurus/plugin-content-docs": "3.9.2", - "@docusaurus/plugin-content-pages": "3.9.2", - "@docusaurus/plugin-css-cascade-layers": "3.9.2", - "@docusaurus/plugin-debug": "3.9.2", - "@docusaurus/plugin-google-analytics": "3.9.2", - "@docusaurus/plugin-google-gtag": "3.9.2", - "@docusaurus/plugin-google-tag-manager": "3.9.2", - "@docusaurus/plugin-sitemap": "3.9.2", - "@docusaurus/plugin-svgr": "3.9.2", - "@docusaurus/theme-classic": "3.9.2", - "@docusaurus/theme-common": "3.9.2", - "@docusaurus/theme-search-algolia": "3.9.2", - "@docusaurus/types": "3.9.2" + "version": "3.10.1", + "resolved": "https://registry.npmjs.org/@docusaurus/preset-classic/-/preset-classic-3.10.1.tgz", + "integrity": "sha512-YO/FL8v1zmbxoTso6mjMz/RDjhaTJxb1UpFFTDdY5847LLDCeyYiYlrhyTbgN1RIN3xnkLKZ9Lj1x8hUzI4JOg==", + "license": "MIT", + "dependencies": { + "@docusaurus/core": "3.10.1", + "@docusaurus/plugin-content-blog": "3.10.1", + "@docusaurus/plugin-content-docs": "3.10.1", + "@docusaurus/plugin-content-pages": "3.10.1", + "@docusaurus/plugin-css-cascade-layers": "3.10.1", + "@docusaurus/plugin-debug": "3.10.1", + "@docusaurus/plugin-google-analytics": "3.10.1", + "@docusaurus/plugin-google-gtag": "3.10.1", + "@docusaurus/plugin-google-tag-manager": "3.10.1", + "@docusaurus/plugin-sitemap": "3.10.1", + "@docusaurus/plugin-svgr": "3.10.1", + "@docusaurus/theme-classic": "3.10.1", + "@docusaurus/theme-common": "3.10.1", + "@docusaurus/theme-search-algolia": "3.10.1", + "@docusaurus/types": "3.10.1" }, "engines": { "node": ">=20.0" @@ -3851,26 +3887,27 @@ } }, "node_modules/@docusaurus/theme-classic": { - "version": "3.9.2", - "resolved": "https://registry.npmjs.org/@docusaurus/theme-classic/-/theme-classic-3.9.2.tgz", - "integrity": "sha512-IGUsArG5hhekXd7RDb11v94ycpJpFdJPkLnt10fFQWOVxAtq5/D7hT6lzc2fhyQKaaCE62qVajOMKL7OiAFAIA==", - "license": "MIT", - "dependencies": { - "@docusaurus/core": "3.9.2", - "@docusaurus/logger": "3.9.2", - "@docusaurus/mdx-loader": "3.9.2", - "@docusaurus/module-type-aliases": "3.9.2", - "@docusaurus/plugin-content-blog": "3.9.2", - "@docusaurus/plugin-content-docs": "3.9.2", - "@docusaurus/plugin-content-pages": "3.9.2", - "@docusaurus/theme-common": "3.9.2", - "@docusaurus/theme-translations": "3.9.2", - "@docusaurus/types": "3.9.2", - "@docusaurus/utils": "3.9.2", - "@docusaurus/utils-common": "3.9.2", - "@docusaurus/utils-validation": "3.9.2", + "version": "3.10.1", + "resolved": "https://registry.npmjs.org/@docusaurus/theme-classic/-/theme-classic-3.10.1.tgz", + "integrity": "sha512-VU1RK0qb2pab0si4r7HFK37cYco8VzqLj3u1PspVipSr/z/GPVKHO4/HXbnePqHoWDk8urjyGSeatH0NIMBM1A==", + "license": "MIT", + "dependencies": { + "@docusaurus/core": "3.10.1", + "@docusaurus/logger": "3.10.1", + "@docusaurus/mdx-loader": "3.10.1", + "@docusaurus/module-type-aliases": "3.10.1", + "@docusaurus/plugin-content-blog": "3.10.1", + "@docusaurus/plugin-content-docs": "3.10.1", + "@docusaurus/plugin-content-pages": "3.10.1", + "@docusaurus/theme-common": "3.10.1", + "@docusaurus/theme-translations": "3.10.1", + "@docusaurus/types": "3.10.1", + "@docusaurus/utils": "3.10.1", + "@docusaurus/utils-common": "3.10.1", + "@docusaurus/utils-validation": "3.10.1", "@mdx-js/react": "^3.0.0", "clsx": "^2.0.0", + "copy-text-to-clipboard": "^3.2.0", "infima": "0.2.0-alpha.45", "lodash": "^4.17.21", "nprogress": "^0.2.0", @@ -3891,15 +3928,15 @@ } }, "node_modules/@docusaurus/theme-common": { - "version": "3.9.2", - "resolved": "https://registry.npmjs.org/@docusaurus/theme-common/-/theme-common-3.9.2.tgz", - "integrity": "sha512-6c4DAbR6n6nPbnZhY2V3tzpnKnGL+6aOsLvFL26VRqhlczli9eWG0VDUNoCQEPnGwDMhPS42UhSAnz5pThm5Ag==", + "version": "3.10.1", + "resolved": "https://registry.npmjs.org/@docusaurus/theme-common/-/theme-common-3.10.1.tgz", + "integrity": "sha512-0YtmIeoNo1fIw65LO8+/1dPgmDV86UmhMkow37gzjytuiCSQm9xob6PJy0L4kuQEMTLfUOGvkXvZr7GPrHquMA==", "license": "MIT", "dependencies": { - "@docusaurus/mdx-loader": "3.9.2", - "@docusaurus/module-type-aliases": "3.9.2", - "@docusaurus/utils": "3.9.2", - "@docusaurus/utils-common": "3.9.2", + "@docusaurus/mdx-loader": "3.10.1", + "@docusaurus/module-type-aliases": "3.10.1", + "@docusaurus/utils": "3.10.1", + "@docusaurus/utils-common": "3.10.1", "@types/history": "^4.7.11", "@types/react": "*", "@types/react-router-config": "*", @@ -3919,19 +3956,20 @@ } }, "node_modules/@docusaurus/theme-search-algolia": { - "version": "3.9.2", - "resolved": "https://registry.npmjs.org/@docusaurus/theme-search-algolia/-/theme-search-algolia-3.9.2.tgz", - "integrity": "sha512-GBDSFNwjnh5/LdkxCKQHkgO2pIMX1447BxYUBG2wBiajS21uj64a+gH/qlbQjDLxmGrbrllBrtJkUHxIsiwRnw==", - "license": "MIT", - "dependencies": { - "@docsearch/react": "^3.9.0 || ^4.1.0", - "@docusaurus/core": "3.9.2", - "@docusaurus/logger": "3.9.2", - "@docusaurus/plugin-content-docs": "3.9.2", - "@docusaurus/theme-common": "3.9.2", - "@docusaurus/theme-translations": "3.9.2", - "@docusaurus/utils": "3.9.2", - "@docusaurus/utils-validation": "3.9.2", + "version": "3.10.1", + "resolved": "https://registry.npmjs.org/@docusaurus/theme-search-algolia/-/theme-search-algolia-3.10.1.tgz", + "integrity": "sha512-OTaARARVZj2GvkJQjB+1jOIxntRaXea+G+fMsNqrZBAU1O1vJKDW22R7kECOHW27oJCLFN9HKaZeRrfAUyviug==", + "license": "MIT", + "dependencies": { + "@algolia/autocomplete-core": "^1.19.2", + "@docsearch/react": "^3.9.0 || ^4.3.2", + "@docusaurus/core": "3.10.1", + "@docusaurus/logger": "3.10.1", + "@docusaurus/plugin-content-docs": "3.10.1", + "@docusaurus/theme-common": "3.10.1", + "@docusaurus/theme-translations": "3.10.1", + "@docusaurus/utils": "3.10.1", + "@docusaurus/utils-validation": "3.10.1", "algoliasearch": "^5.37.0", "algoliasearch-helper": "^3.26.0", "clsx": "^2.0.0", @@ -3950,9 +3988,9 @@ } }, "node_modules/@docusaurus/theme-translations": { - "version": "3.9.2", - "resolved": "https://registry.npmjs.org/@docusaurus/theme-translations/-/theme-translations-3.9.2.tgz", - "integrity": "sha512-vIryvpP18ON9T9rjgMRFLr2xJVDpw1rtagEGf8Ccce4CkTrvM/fRB8N2nyWYOW5u3DdjkwKw5fBa+3tbn9P4PA==", + "version": "3.10.1", + "resolved": "https://registry.npmjs.org/@docusaurus/theme-translations/-/theme-translations-3.10.1.tgz", + "integrity": "sha512-cLMyaKivjBVWKMJuWqyFVVgtqe8DPJNPkog0bn8W1MDVAKcPdxRFycBfC1We1RaNp7Rdk513bmtW78RR6OBxBw==", "license": "MIT", "dependencies": { "fs-extra": "^11.1.1", @@ -3963,9 +4001,9 @@ } }, "node_modules/@docusaurus/types": { - "version": "3.9.2", - "resolved": "https://registry.npmjs.org/@docusaurus/types/-/types-3.9.2.tgz", - "integrity": "sha512-Ux1JUNswg+EfUEmajJjyhIohKceitY/yzjRUpu04WXgvVz+fbhVC0p+R0JhvEu4ytw8zIAys2hrdpQPBHRIa8Q==", + "version": "3.10.1", + "resolved": "https://registry.npmjs.org/@docusaurus/types/-/types-3.10.1.tgz", + "integrity": "sha512-XYMK8k1szDCFMw2V+Xyen0g7Kee1sP3dtFnl7vkGkZOkeAJ/oPDQPL8iz4HBKOo/cwU8QeV6onVjMqtP+tFzsw==", "license": "MIT", "dependencies": { "@mdx-js/mdx": "^3.0.0", @@ -3999,16 +4037,16 @@ } }, "node_modules/@docusaurus/utils": { - "version": "3.9.2", - "resolved": "https://registry.npmjs.org/@docusaurus/utils/-/utils-3.9.2.tgz", - "integrity": "sha512-lBSBiRruFurFKXr5Hbsl2thmGweAPmddhF3jb99U4EMDA5L+e5Y1rAkOS07Nvrup7HUMBDrCV45meaxZnt28nQ==", + "version": "3.10.1", + "resolved": "https://registry.npmjs.org/@docusaurus/utils/-/utils-3.10.1.tgz", + "integrity": "sha512-3ojeJry9xBYdJO6qoyyzqeJFSJBVx2mXhyDzSdjwL2+URFQMf+h25gG38iswGImicK0ELjTd1EL2xzk8hf3QPw==", "license": "MIT", "dependencies": { - "@docusaurus/logger": "3.9.2", - "@docusaurus/types": "3.9.2", - "@docusaurus/utils-common": "3.9.2", + "@docusaurus/logger": "3.10.1", + "@docusaurus/types": "3.10.1", + "@docusaurus/utils-common": "3.10.1", "escape-string-regexp": "^4.0.0", - "execa": "5.1.1", + "execa": "^5.1.1", "file-loader": "^6.2.0", "fs-extra": "^11.1.1", "github-slugger": "^1.5.0", @@ -4031,12 +4069,12 @@ } }, "node_modules/@docusaurus/utils-common": { - "version": "3.9.2", - "resolved": "https://registry.npmjs.org/@docusaurus/utils-common/-/utils-common-3.9.2.tgz", - "integrity": "sha512-I53UC1QctruA6SWLvbjbhCpAw7+X7PePoe5pYcwTOEXD/PxeP8LnECAhTHHwWCblyUX5bMi4QLRkxvyZ+IT8Aw==", + "version": "3.10.1", + "resolved": "https://registry.npmjs.org/@docusaurus/utils-common/-/utils-common-3.10.1.tgz", + "integrity": "sha512-5mFSgEADtnFxFH7RLw02QA5MpU5JVUCj0MPeIvi/aF4Fi45tQRIuTwXoXDqJ+1VfQJuYJGz3SI63wmGz4HvXzA==", "license": "MIT", "dependencies": { - "@docusaurus/types": "3.9.2", + "@docusaurus/types": "3.10.1", "tslib": "^2.6.0" }, "engines": { @@ -4044,14 +4082,14 @@ } }, "node_modules/@docusaurus/utils-validation": { - "version": "3.9.2", - "resolved": "https://registry.npmjs.org/@docusaurus/utils-validation/-/utils-validation-3.9.2.tgz", - "integrity": "sha512-l7yk3X5VnNmATbwijJkexdhulNsQaNDwoagiwujXoxFbWLcxHQqNQ+c/IAlzrfMMOfa/8xSBZ7KEKDesE/2J7A==", + "version": "3.10.1", + "resolved": "https://registry.npmjs.org/@docusaurus/utils-validation/-/utils-validation-3.10.1.tgz", + "integrity": "sha512-cRv1X69jwaWv47waglllgZVWzeBFLhl53XT/XED/83BerVBTC5FTP8WTcVl8Z6sZOegDSwitu/wpCSPCDOT6lg==", "license": "MIT", "dependencies": { - "@docusaurus/logger": "3.9.2", - "@docusaurus/utils": "3.9.2", - "@docusaurus/utils-common": "3.9.2", + "@docusaurus/logger": "3.10.1", + "@docusaurus/utils": "3.10.1", + "@docusaurus/utils-common": "3.10.1", "fs-extra": "^11.2.0", "joi": "^17.9.2", "js-yaml": "^4.1.0", @@ -4618,7 +4656,6 @@ "resolved": "https://registry.npmjs.org/@mdx-js/react/-/react-3.1.1.tgz", "integrity": "sha512-f++rKLQgUVYDAtECQ6fn/is15GkEH9+nZPM3MS0RcxVqoTfawHvDlSCH7JbMhAM6uJ32v3eXLvLmLvjGu7PTQw==", "license": "MIT", - "peer": true, "dependencies": { "@types/mdx": "^2.0.0" }, @@ -5082,7 +5119,6 @@ "resolved": "https://registry.npmjs.org/@svgr/core/-/core-8.1.0.tgz", "integrity": "sha512-8QqtOQT5ACVlmsvKOJNEaWmRPmcojMOzCz4Hs2BGG/toAp/K38LcsMRyLp349glq5AzJbCEeimEoxaX6v/fLrA==", "license": "MIT", - "peer": true, "dependencies": { "@babel/core": "^7.21.3", "@svgr/babel-preset": "8.1.0", @@ -5232,9 +5268,9 @@ } }, "node_modules/@types/debug": { - "version": "4.1.12", - "resolved": "https://registry.npmjs.org/@types/debug/-/debug-4.1.12.tgz", - "integrity": "sha512-vIChWdVG3LG1SMxEvI/AK+FWJthlrqlTu7fbrlywTkkaONwk/UAGaULXRlf8vkzFBLVm0zkMdCquhL5aOjhXPQ==", + "version": "4.1.13", + "resolved": "https://registry.npmjs.org/@types/debug/-/debug-4.1.13.tgz", + "integrity": "sha512-KSVgmQmzMwPlmtljOomayoR89W4FynCAi3E8PPs7vmDVPe84hT+vGPKkJfThkmXs0x0jAaa9U8uW8bbfyS2fWw==", "license": "MIT", "dependencies": { "@types/ms": "*" @@ -5300,9 +5336,9 @@ } }, "node_modules/@types/gtag.js": { - "version": "0.0.12", - "resolved": "https://registry.npmjs.org/@types/gtag.js/-/gtag.js-0.0.12.tgz", - "integrity": "sha512-YQV9bUsemkzG81Ea295/nF/5GijnD2Af7QhEofh7xu+kvCN6RdodgNwwGWXB5GMI3NoyvQo0odNctoH/qLMIpg==", + "version": "0.0.20", + "resolved": "https://registry.npmjs.org/@types/gtag.js/-/gtag.js-0.0.20.tgz", + "integrity": "sha512-wwAbk3SA2QeU67unN7zPxjEHmPmlXwZXZvQEpbEUQuMCRGgKyE1m6XDuTUA9b6pCGb/GqJmdfMOY5LuDjJSbbg==", "license": "MIT" }, "node_modules/@types/hast": { @@ -5436,7 +5472,6 @@ "resolved": "https://registry.npmjs.org/@types/react/-/react-19.2.14.tgz", "integrity": "sha512-ilcTH/UniCkMdtexkoCN0bI7pMcJDvmQFPvuPvmEaYA/NSfFTAgdUSLAoVjaRJm7+6PvcM+q1zYOwS4wTYMF9w==", "license": "MIT", - "peer": true, "dependencies": { "csstype": "^3.2.2" } @@ -5567,9 +5602,9 @@ "license": "MIT" }, "node_modules/@ungap/structured-clone": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/@ungap/structured-clone/-/structured-clone-1.3.0.tgz", - "integrity": "sha512-WmoN8qaIAo7WTYWbAZuG8PYEhn5fkz7dZrqTBZ7dtt//lL2Gwms1IcnQ5yHqjDfX8Ft5j4YzDM23f87zBfDe9g==", + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/@ungap/structured-clone/-/structured-clone-1.3.1.tgz", + "integrity": "sha512-mUFwbeTqrVgDQxFveS+df2yfap6iuP20NAKAsBt5jDEoOTDew+zwLAOilHCeQJOVSvmgCX4ogqIrA0mnyr08yQ==", "license": "ISC" }, "node_modules/@webassemblyjs/ast": { @@ -5778,7 +5813,6 @@ "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.16.0.tgz", "integrity": "sha512-UVJyE9MttOsBQIDKw1skb9nAwQuR5wuGD3+82K6JgJlm/Y+KI92oNsMNGZCYdDsVtRHSak0pcV5Dno5+4jh9sw==", "license": "MIT", - "peer": true, "bin": { "acorn": "bin/acorn" }, @@ -5846,7 +5880,6 @@ "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.18.0.tgz", "integrity": "sha512-PlXPeEWMXMZ7sPYOHqmDyCJzcfNrUr3fGNKtezX14ykXOEIvyK81d+qydx89KY5O71FKMPaQ2vBfBFI5NHR63A==", "license": "MIT", - "peer": true, "dependencies": { "fast-deep-equal": "^3.1.3", "fast-uri": "^3.0.1", @@ -5888,35 +5921,34 @@ } }, "node_modules/algoliasearch": { - "version": "5.49.1", - "resolved": "https://registry.npmjs.org/algoliasearch/-/algoliasearch-5.49.1.tgz", - "integrity": "sha512-X3Pp2aRQhg4xUC6PQtkubn5NpRKuUPQ9FPDQlx36SmpFwwH2N0/tw4c+NXV3nw3PsgeUs+BuWGP0gjz3TvENLQ==", - "license": "MIT", - "peer": true, - "dependencies": { - "@algolia/abtesting": "1.15.1", - "@algolia/client-abtesting": "5.49.1", - "@algolia/client-analytics": "5.49.1", - "@algolia/client-common": "5.49.1", - "@algolia/client-insights": "5.49.1", - "@algolia/client-personalization": "5.49.1", - "@algolia/client-query-suggestions": "5.49.1", - "@algolia/client-search": "5.49.1", - "@algolia/ingestion": "1.49.1", - "@algolia/monitoring": "1.49.1", - "@algolia/recommend": "5.49.1", - "@algolia/requester-browser-xhr": "5.49.1", - "@algolia/requester-fetch": "5.49.1", - "@algolia/requester-node-http": "5.49.1" + "version": "5.52.1", + "resolved": "https://registry.npmjs.org/algoliasearch/-/algoliasearch-5.52.1.tgz", + "integrity": "sha512-fHA8+kXTbjagw3jkLiaS7KKrH8qe2DyOsiUhGlN4cdT77PEsfqXZl7ewDk1hsg+pJnPlnE50XtLxjR91iJOpmg==", + "license": "MIT", + "dependencies": { + "@algolia/abtesting": "1.18.1", + "@algolia/client-abtesting": "5.52.1", + "@algolia/client-analytics": "5.52.1", + "@algolia/client-common": "5.52.1", + "@algolia/client-insights": "5.52.1", + "@algolia/client-personalization": "5.52.1", + "@algolia/client-query-suggestions": "5.52.1", + "@algolia/client-search": "5.52.1", + "@algolia/ingestion": "1.52.1", + "@algolia/monitoring": "1.52.1", + "@algolia/recommend": "5.52.1", + "@algolia/requester-browser-xhr": "5.52.1", + "@algolia/requester-fetch": "5.52.1", + "@algolia/requester-node-http": "5.52.1" }, "engines": { "node": ">= 14.0.0" } }, "node_modules/algoliasearch-helper": { - "version": "3.28.0", - "resolved": "https://registry.npmjs.org/algoliasearch-helper/-/algoliasearch-helper-3.28.0.tgz", - "integrity": "sha512-GBN0xsxGggaCPElZq24QzMdfphrjIiV2xA+hRXE4/UMpN3nsF2WrM8q+x80OGvGpJWtB7F+4Hq5eSfWwuejXrg==", + "version": "3.29.1", + "resolved": "https://registry.npmjs.org/algoliasearch-helper/-/algoliasearch-helper-3.29.1.tgz", + "integrity": "sha512-6ck2YFudF2Pje7szQoPBiRFTGfd+1I+0I/WfLPGn0bj1kvrFoOQmNyedNiDxTk3/r4IfSLDYk+RA4G7u8H6+yA==", "license": "MIT", "dependencies": { "@algolia/events": "^4.0.1" @@ -5954,33 +5986,6 @@ "node": ">=8" } }, - "node_modules/ansi-escapes": { - "version": "4.3.2", - "resolved": "https://registry.npmjs.org/ansi-escapes/-/ansi-escapes-4.3.2.tgz", - "integrity": "sha512-gKXj5ALrKWQLsYG9jlTRmR/xKluxHV+Z9QEwNIgCfM1/uwPMCuzVVnh5mwTd+OuBZcwSIMbqssNWRm1lE51QaQ==", - "license": "MIT", - "dependencies": { - "type-fest": "^0.21.3" - }, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/ansi-escapes/node_modules/type-fest": { - "version": "0.21.3", - "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.21.3.tgz", - "integrity": "sha512-t0rzBq87m3fVcduHDUFhKmyyX+9eo6WQjZvf51Ea/M0Q7+T374Jp1aUiyUl0GKxp8M/OETVHSDvmkyPgvX+X2w==", - "license": "(MIT OR CC0-1.0)", - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, "node_modules/ansi-html-community": { "version": "0.0.8", "resolved": "https://registry.npmjs.org/ansi-html-community/-/ansi-html-community-0.0.8.tgz", @@ -6017,6 +6022,15 @@ "url": "https://github.com/chalk/ansi-styles?sponsor=1" } }, + "node_modules/ansis": { + "version": "3.17.0", + "resolved": "https://registry.npmjs.org/ansis/-/ansis-3.17.0.tgz", + "integrity": "sha512-0qWUglt9JEqLFr3w1I1pbrChn1grhaiAR2ocX1PP/flRmxgtwTzPFFFnfIlD6aMOLQZgSuCRlidD70lvx8yhzg==", + "license": "ISC", + "engines": { + "node": ">=14" + } + }, "node_modules/anymatch": { "version": "3.1.3", "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.3.tgz", @@ -6081,9 +6095,9 @@ } }, "node_modules/autoprefixer": { - "version": "10.4.27", - "resolved": "https://registry.npmjs.org/autoprefixer/-/autoprefixer-10.4.27.tgz", - "integrity": "sha512-NP9APE+tO+LuJGn7/9+cohklunJsXWiaWEfV3si4Gi/XHDwVNgkwr1J3RQYFIvPy76GmJ9/bW8vyoU1LcxwKHA==", + "version": "10.5.0", + "resolved": "https://registry.npmjs.org/autoprefixer/-/autoprefixer-10.5.0.tgz", + "integrity": "sha512-FMhOoZV4+qR6aTUALKX2rEqGG+oyATvwBt9IIzVR5rMa2HRWPkxf+P+PAJLD1I/H5/II+HuZcBJYEFBpq39ong==", "funding": [ { "type": "opencollective", @@ -6100,8 +6114,8 @@ ], "license": "MIT", "dependencies": { - "browserslist": "^4.28.1", - "caniuse-lite": "^1.0.30001774", + "browserslist": "^4.28.2", + "caniuse-lite": "^1.0.30001787", "fraction.js": "^5.3.4", "picocolors": "^1.1.1", "postcss-value-parser": "^4.2.0" @@ -6143,13 +6157,13 @@ } }, "node_modules/babel-plugin-polyfill-corejs2": { - "version": "0.4.15", - "resolved": "https://registry.npmjs.org/babel-plugin-polyfill-corejs2/-/babel-plugin-polyfill-corejs2-0.4.15.tgz", - "integrity": "sha512-hR3GwrRwHUfYwGfrisXPIDP3JcYfBrW7wKE7+Au6wDYl7fm/ka1NEII6kORzxNU556JjfidZeBsO10kYvtV1aw==", + "version": "0.4.17", + "resolved": "https://registry.npmjs.org/babel-plugin-polyfill-corejs2/-/babel-plugin-polyfill-corejs2-0.4.17.tgz", + "integrity": "sha512-aTyf30K/rqAsNwN76zYrdtx8obu0E4KoUME29B1xj+B3WxgvWkp943vYQ+z8Mv3lw9xHXMHpvSPOBxzAkIa94w==", "license": "MIT", "dependencies": { "@babel/compat-data": "^7.28.6", - "@babel/helper-define-polyfill-provider": "^0.6.6", + "@babel/helper-define-polyfill-provider": "^0.6.8", "semver": "^6.3.1" }, "peerDependencies": { @@ -6179,12 +6193,12 @@ } }, "node_modules/babel-plugin-polyfill-regenerator": { - "version": "0.6.6", - "resolved": "https://registry.npmjs.org/babel-plugin-polyfill-regenerator/-/babel-plugin-polyfill-regenerator-0.6.6.tgz", - "integrity": "sha512-hYm+XLYRMvupxiQzrvXUj7YyvFFVfv5gI0R71AJzudg1g2AI2vyCPPIFEBjk162/wFzti3inBHo7isWFuEVS/A==", + "version": "0.6.8", + "resolved": "https://registry.npmjs.org/babel-plugin-polyfill-regenerator/-/babel-plugin-polyfill-regenerator-0.6.8.tgz", + "integrity": "sha512-M762rNHfSF1EV3SLtnCJXFoQbbIIz0OyRwnCmV0KPC7qosSfCO0QLTSuJX3ayAebubhE6oYBAYPrBA5ljowaZg==", "license": "MIT", "dependencies": { - "@babel/helper-define-polyfill-provider": "^0.6.6" + "@babel/helper-define-polyfill-provider": "^0.6.8" }, "peerDependencies": { "@babel/core": "^7.4.0 || ^8.0.0-0 <8.0.0" @@ -6207,9 +6221,9 @@ "license": "MIT" }, "node_modules/baseline-browser-mapping": { - "version": "2.10.0", - "resolved": "https://registry.npmjs.org/baseline-browser-mapping/-/baseline-browser-mapping-2.10.0.tgz", - "integrity": "sha512-lIyg0szRfYbiy67j9KN8IyeD7q7hcmqnJ1ddWmNt19ItGpNN64mnllmxUNFIOdOm6by97jlL6wfpTTJrmnjWAA==", + "version": "2.10.29", + "resolved": "https://registry.npmjs.org/baseline-browser-mapping/-/baseline-browser-mapping-2.10.29.tgz", + "integrity": "sha512-Asa2krT+XTPZINCS+2QcyS8WTkObE77RwkydwF7h6DmnKqbvlalz93m/dnphUyCa6SWSP51VgtEUf2FN+gelFQ==", "license": "Apache-2.0", "bin": { "baseline-browser-mapping": "dist/cli.cjs" @@ -6332,9 +6346,9 @@ } }, "node_modules/brace-expansion": { - "version": "1.1.12", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.12.tgz", - "integrity": "sha512-9T9UjW3r0UW5c1Q7GTwllptXwhvYmEzFhzMfZ9H7FQWt+uZePjZPjBP/W1ZEyZ1twGWom5/56TF4lPcqjnDHcg==", + "version": "1.1.14", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.14.tgz", + "integrity": "sha512-MWPGfDxnyzKU7rNOW9SP/c50vi3xrmrua/+6hfPbCS2ABNWfx24vPidzvC7krjU/RTo235sV776ymlsMtGKj8g==", "license": "MIT", "dependencies": { "balanced-match": "^1.0.0", @@ -6354,9 +6368,9 @@ } }, "node_modules/browserslist": { - "version": "4.28.1", - "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.28.1.tgz", - "integrity": "sha512-ZC5Bd0LgJXgwGqUknZY/vkUQ04r8NXnJZ3yYi4vDmSiZmC/pdSN0NbNRPxZpbtO4uAfDUAFffO8IZoM3Gj8IkA==", + "version": "4.28.2", + "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.28.2.tgz", + "integrity": "sha512-48xSriZYYg+8qXna9kwqjIVzuQxi+KYWp2+5nCYnYKPTr0LvD89Jqk2Or5ogxz0NUMfIjhh2lIUX/LyX9B4oIg==", "funding": [ { "type": "opencollective", @@ -6372,13 +6386,12 @@ } ], "license": "MIT", - "peer": true, "dependencies": { - "baseline-browser-mapping": "^2.9.0", - "caniuse-lite": "^1.0.30001759", - "electron-to-chromium": "^1.5.263", - "node-releases": "^2.0.27", - "update-browserslist-db": "^1.2.0" + "baseline-browser-mapping": "^2.10.12", + "caniuse-lite": "^1.0.30001782", + "electron-to-chromium": "^1.5.328", + "node-releases": "^2.0.36", + "update-browserslist-db": "^1.2.3" }, "bin": { "browserslist": "cli.js" @@ -6454,14 +6467,14 @@ } }, "node_modules/call-bind": { - "version": "1.0.8", - "resolved": "https://registry.npmjs.org/call-bind/-/call-bind-1.0.8.tgz", - "integrity": "sha512-oKlSFMcMwpUg2ednkhQ454wfWiU/ul3CkJe/PEHcTKuiX6RpbehUiFMXu13HalGZxfUwCQzZG747YXBn1im9ww==", + "version": "1.0.9", + "resolved": "https://registry.npmjs.org/call-bind/-/call-bind-1.0.9.tgz", + "integrity": "sha512-a/hy+pNsFUTR+Iz8TCJvXudKVLAnz/DyeSUo10I5yvFDQJBFU2s9uqQpoSrJlroHUKoKqzg+epxyP9lqFdzfBQ==", "license": "MIT", "dependencies": { - "call-bind-apply-helpers": "^1.0.0", - "es-define-property": "^1.0.0", - "get-intrinsic": "^1.2.4", + "call-bind-apply-helpers": "^1.0.2", + "es-define-property": "^1.0.1", + "get-intrinsic": "^1.3.0", "set-function-length": "^1.2.2" }, "engines": { @@ -6544,9 +6557,9 @@ } }, "node_modules/caniuse-lite": { - "version": "1.0.30001777", - "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001777.tgz", - "integrity": "sha512-tmN+fJxroPndC74efCdp12j+0rk0RHwV5Jwa1zWaFVyw2ZxAuPeG8ZgWC3Wz7uSjT3qMRQ5XHZ4COgQmsCMJAQ==", + "version": "1.0.30001792", + "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001792.tgz", + "integrity": "sha512-hVLMUZFgR4JJ6ACt1uEESvQN1/dBVqPAKY0hgrV70eN3391K6juAfTjKZLKvOMsx8PxA7gsY1/tLMMTcfFLLpw==", "funding": [ { "type": "opencollective", @@ -7059,6 +7072,18 @@ "integrity": "sha512-NXdYc3dLr47pBkpUCHtKSwIOQXLVn8dZEuywboCOJY/osA0wFSLlSawr3KN8qXJEyX66FcONTH8EIlVuK0yyFA==", "license": "MIT" }, + "node_modules/copy-text-to-clipboard": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/copy-text-to-clipboard/-/copy-text-to-clipboard-3.2.2.tgz", + "integrity": "sha512-T6SqyLd1iLuqPA90J5N4cTalrtovCySh58iiZDGJ6FGznbclKh4UI+FGacQSgFzwKG77W7XT5gwbVEbd9cIH1A==", + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/copy-webpack-plugin": { "version": "11.0.0", "resolved": "https://registry.npmjs.org/copy-webpack-plugin/-/copy-webpack-plugin-11.0.0.tgz", @@ -7138,9 +7163,9 @@ } }, "node_modules/core-js-compat": { - "version": "3.48.0", - "resolved": "https://registry.npmjs.org/core-js-compat/-/core-js-compat-3.48.0.tgz", - "integrity": "sha512-OM4cAF3D6VtH/WkLtWvyNC56EZVXsZdU3iqaMG2B4WvYrlqU831pc4UtG5yp0sE9z8Y02wVN7PjW5Zf9Gt0f1Q==", + "version": "3.49.0", + "resolved": "https://registry.npmjs.org/core-js-compat/-/core-js-compat-3.49.0.tgz", + "integrity": "sha512-VQXt1jr9cBz03b331DFDCCP90b3fanciLkgiOoy8SBHy06gNf+vQ1A3WFLqG7I8TipYIKeYK9wxd0tUrvHcOZA==", "license": "MIT", "dependencies": { "browserslist": "^4.28.1" @@ -7150,17 +7175,6 @@ "url": "https://opencollective.com/core-js" } }, - "node_modules/core-js-pure": { - "version": "3.48.0", - "resolved": "https://registry.npmjs.org/core-js-pure/-/core-js-pure-3.48.0.tgz", - "integrity": "sha512-1slJgk89tWC51HQ1AEqG+s2VuwpTRr8ocu4n20QUcH1v9lAN0RXen0Q0AABa/DK1I7RrNWLucplOHMx8hfTGTw==", - "hasInstallScript": true, - "license": "MIT", - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/core-js" - } - }, "node_modules/core-util-is": { "version": "1.0.3", "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.3.tgz", @@ -7273,9 +7287,9 @@ } }, "node_modules/css-declaration-sorter": { - "version": "7.3.1", - "resolved": "https://registry.npmjs.org/css-declaration-sorter/-/css-declaration-sorter-7.3.1.tgz", - "integrity": "sha512-gz6x+KkgNCjxq3Var03pRYLhyNfwhkKF1g/yoLgDNtFvVu0/fOLV9C8fFEZRjACp/XQLumjAYo7JVjzH3wLbxA==", + "version": "7.4.0", + "resolved": "https://registry.npmjs.org/css-declaration-sorter/-/css-declaration-sorter-7.4.0.tgz", + "integrity": "sha512-LTuzjPoyA2vMGKKcaOqKSp7Ub2eGrNfKiZH4LpezxpNrsICGCSFvsQOI29psISxNZtaXibkC2CXzrQ5enMeGGw==", "license": "ISC", "engines": { "node": "^14 || ^16 || >=18" @@ -7338,7 +7352,6 @@ "resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-7.1.1.tgz", "integrity": "sha512-orRsuYpJVw8LdAwqqLykBj9ecS5/cRHlI5+nvTo8LcCKmzDmqVORXtOIYEEQuL9D4BxtA1lm5isAqzQZCoQ6Eg==", "license": "MIT", - "peer": true, "dependencies": { "cssesc": "^3.0.0", "util-deprecate": "^1.0.2" @@ -7490,9 +7503,9 @@ } }, "node_modules/cssdb": { - "version": "8.8.0", - "resolved": "https://registry.npmjs.org/cssdb/-/cssdb-8.8.0.tgz", - "integrity": "sha512-QbLeyz2Bgso1iRlh7IpWk6OKa3lLNGXsujVjDMPl9rOZpxKeiG69icLpbLCFxeURwmcdIfZqQyhlooKJYM4f8Q==", + "version": "8.8.1", + "resolved": "https://registry.npmjs.org/cssdb/-/cssdb-8.8.1.tgz", + "integrity": "sha512-PdLTDamqN1muXEmfQggrogLmD+ZjfOhlZsFFs28tYSTqnlk6gEwg5wQCt6wLl2HstegUYgof6GrYyXXODFDC5g==", "funding": [ { "type": "opencollective", @@ -8033,9 +8046,9 @@ "license": "MIT" }, "node_modules/electron-to-chromium": { - "version": "1.5.307", - "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.5.307.tgz", - "integrity": "sha512-5z3uFKBWjiNR44nFcYdkcXjKMbg5KXNdciu7mhTPo9tB7NbqSNP2sSnGR+fqknZSCwKkBN+oxiiajWs4dT6ORg==", + "version": "1.5.353", + "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.5.353.tgz", + "integrity": "sha512-kOrWphBi8TOZyiJZqsgqIle0lw+tzmnQK83pV9dZUd01Nm2POECSyFQMAuarzZdYqQW7FH9RaYOuaRo3h+bQ3w==", "license": "ISC" }, "node_modules/emoji-regex": { @@ -8532,9 +8545,9 @@ "license": "MIT" }, "node_modules/express/node_modules/path-to-regexp": { - "version": "0.1.12", - "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-0.1.12.tgz", - "integrity": "sha512-RA1GjUVMnvYFxuqovrEqZoxxW5NUZqbwKtYz/Tt7nXerk0LbLblQmrsgdeOxV5SFHf0UDggjS/bSeOZwt1pmEQ==", + "version": "0.1.13", + "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-0.1.13.tgz", + "integrity": "sha512-A/AGNMFN3c8bOlvV9RreMdrv7jsmF9XIfDeCd87+I8RNg6s78BhJxMu69NEMHBSJFxKidViTEdruRwEk/WIKqA==", "license": "MIT" }, "node_modules/express/node_modules/range-parser": { @@ -8593,9 +8606,9 @@ "license": "MIT" }, "node_modules/fast-uri": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/fast-uri/-/fast-uri-3.1.0.tgz", - "integrity": "sha512-iPeeDKJSWf4IEOasVVrknXpaBV0IApz/gp7S2bb7Z4Lljbl2MGJRqInZiUrQwV16cpzw/D3S5j5Julj/gT52AA==", + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/fast-uri/-/fast-uri-3.1.2.tgz", + "integrity": "sha512-rVjf7ArG3LTk+FS6Yw81V1DLuZl1bRbNrev6Tmd/9RaroeeRRJhAt7jg/6YFxbvAQXUCavSoZhPPj6oOx+5KjQ==", "funding": [ { "type": "github", @@ -8654,30 +8667,6 @@ "node": ">=0.4.0" } }, - "node_modules/figures": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/figures/-/figures-3.2.0.tgz", - "integrity": "sha512-yaduQFRKLXYOGgEn6AZau90j3ggSOyiqXU0F9JZfeXYhNa+Jk4X+s45A2zg5jns87GAFa34BBm2kXw4XpNcbdg==", - "license": "MIT", - "dependencies": { - "escape-string-regexp": "^1.0.5" - }, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/figures/node_modules/escape-string-regexp": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", - "integrity": "sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg==", - "license": "MIT", - "engines": { - "node": ">=0.8.0" - } - }, "node_modules/file-loader": { "version": "6.2.0", "resolved": "https://registry.npmjs.org/file-loader/-/file-loader-6.2.0.tgz", @@ -8699,11 +8688,10 @@ } }, "node_modules/file-loader/node_modules/ajv": { - "version": "6.14.0", - "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.14.0.tgz", - "integrity": "sha512-IWrosm/yrn43eiKqkfkHis7QioDleaXQHdDVPKg0FSwwd/DuvyX79TZnFOnYpB7dcsFAMmtFztZuXPDvSePkFw==", + "version": "6.15.0", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.15.0.tgz", + "integrity": "sha512-fgFx7Hfoq60ytK2c7DhnF8jIvzYgOMxfugjLOSMHjLIPgenqa7S7oaagATUq99mV6IYvN2tRmC0wnTYX6iPbMw==", "license": "MIT", - "peer": true, "dependencies": { "fast-deep-equal": "^3.1.1", "fast-json-stable-stringify": "^2.0.0", @@ -8835,9 +8823,9 @@ } }, "node_modules/follow-redirects": { - "version": "1.15.11", - "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.15.11.tgz", - "integrity": "sha512-deG2P0JfjrTxl50XGCDyfI97ZGVCxIpfKYmfyrQ54n5FO/0gfIES8C/Psl6kWVDolizcaaxZJnTS0QSMxvnsBQ==", + "version": "1.16.0", + "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.16.0.tgz", + "integrity": "sha512-y5rN/uOsadFT/JfYwhxRS5R7Qce+g3zG97+JrtFZlC9klX/W5hD7iiLzScI4nZqUS7DNUdhPgw4xI8W2LuXlUw==", "funding": [ { "type": "individual", @@ -9237,9 +9225,9 @@ } }, "node_modules/hasown": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/hasown/-/hasown-2.0.2.tgz", - "integrity": "sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==", + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/hasown/-/hasown-2.0.3.tgz", + "integrity": "sha512-ej4AhfhfL2Q2zpMmLo7U1Uv9+PyhIZpgQLGT1F9miIGmiCJIoCgSmczFdrc97mWT4kVY72KA+WnnhJ5pghSvSg==", "license": "MIT", "dependencies": { "function-bind": "^1.1.2" @@ -9939,12 +9927,12 @@ } }, "node_modules/is-core-module": { - "version": "2.16.1", - "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.16.1.tgz", - "integrity": "sha512-UfoeMA6fIJ8wTYFEUjelnaGI67v6+N7qXJEvQuIGa99l4xsCruSYOVSQ0uPANn4dAzm8lkYPaKLrrijLq7x23w==", + "version": "2.16.2", + "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.16.2.tgz", + "integrity": "sha512-evOr8xfXKxE6qSR0hSXL2r3sd7ALj8+7jQEUvPYcm5sgZFdJ+AYzT6yNmJenvIYQBgIGwfwz08sL8zoL7yq2BA==", "license": "MIT", "dependencies": { - "hasown": "^2.0.2" + "hasown": "^2.0.3" }, "engines": { "node": ">= 0.4" @@ -10483,9 +10471,9 @@ } }, "node_modules/lodash": { - "version": "4.17.23", - "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.23.tgz", - "integrity": "sha512-LgVTMpQtIopCi79SJeDiP0TfWi5CNEc/L/aRdTh3yIvmZXTnheWpKjSZhnvMl8iXbC1tFg9gdHHDMLoV7CnG+w==", + "version": "4.18.1", + "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.18.1.tgz", + "integrity": "sha512-dMInicTPVE8d1e5otfwmmjlxkZoUpiVLwyeTdUsi/Caj/gfzzblBcCE5sRHV/AsjuCmxWrte2TNGSYuCeCq+0Q==", "license": "MIT" }, "node_modules/lodash.debounce": { @@ -12920,9 +12908,9 @@ } }, "node_modules/mini-css-extract-plugin": { - "version": "2.10.0", - "resolved": "https://registry.npmjs.org/mini-css-extract-plugin/-/mini-css-extract-plugin-2.10.0.tgz", - "integrity": "sha512-540P2c5dYnJlyJxTaSloliZexv8rji6rY8FhQN+WF/82iHQfA23j/xtJx97L+mXOML27EqksSek/g4eK7jaL3g==", + "version": "2.10.2", + "resolved": "https://registry.npmjs.org/mini-css-extract-plugin/-/mini-css-extract-plugin-2.10.2.tgz", + "integrity": "sha512-AOSS0IdEB95ayVkxn5oGzNQwqAi2J0Jb/kKm43t7H73s8+f5873g0yuj0PNvK4dO75mu5DHg4nlgp4k6Kga8eg==", "license": "MIT", "dependencies": { "schema-utils": "^4.0.0", @@ -12995,9 +12983,9 @@ } }, "node_modules/nanoid": { - "version": "3.3.11", - "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.11.tgz", - "integrity": "sha512-N8SpfPUnUp1bK+PMYW8qSWdl9U+wwNWI4QKxOYDy9JAro3WMX7p2OeVRF9v+347pnakNevPmiHhNmZ2HbFA76w==", + "version": "3.3.12", + "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.12.tgz", + "integrity": "sha512-ZB9RH/39qpq5Vu6Y+NmUaFhQR6pp+M2Xt76XBnEwDaGcVAqhlvxrl3B2bKS5D3NH3QR76v3aSrKaF/Kiy7lEtQ==", "funding": [ { "type": "github", @@ -13130,11 +13118,10 @@ } }, "node_modules/null-loader/node_modules/ajv": { - "version": "6.14.0", - "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.14.0.tgz", - "integrity": "sha512-IWrosm/yrn43eiKqkfkHis7QioDleaXQHdDVPKg0FSwwd/DuvyX79TZnFOnYpB7dcsFAMmtFztZuXPDvSePkFw==", + "version": "6.15.0", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.15.0.tgz", + "integrity": "sha512-fgFx7Hfoq60ytK2c7DhnF8jIvzYgOMxfugjLOSMHjLIPgenqa7S7oaagATUq99mV6IYvN2tRmC0wnTYX6iPbMw==", "license": "MIT", - "peer": true, "dependencies": { "fast-deep-equal": "^3.1.1", "fast-json-stable-stringify": "^2.0.0", @@ -13605,9 +13592,9 @@ "license": "ISC" }, "node_modules/picomatch": { - "version": "2.3.1", - "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz", - "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==", + "version": "2.3.2", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.2.tgz", + "integrity": "sha512-V7+vQEJ06Z+c5tSye8S+nHUfI51xoXIXjHQ99cQtKUkQqqO1kO/KCJUfZXuB47h/YBlDhah2H3hdUGXn8ie0oA==", "license": "MIT", "engines": { "node": ">=8.6" @@ -13649,9 +13636,9 @@ } }, "node_modules/postcss": { - "version": "8.5.8", - "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.5.8.tgz", - "integrity": "sha512-OW/rX8O/jXnm82Ey1k44pObPtdblfiuWnrd8X7GJ7emImCOstunGbXUpp7HdBrFQX6rJzn3sPT397Wp5aCwCHg==", + "version": "8.5.14", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.5.14.tgz", + "integrity": "sha512-SoSL4+OSEtR99LHFZQiJLkT59C5B1amGO1NzTwj7TT1qCUgUO6hxOvzkOYxD+vMrXBM3XJIKzokoERdqQq/Zmg==", "funding": [ { "type": "opencollective", @@ -13667,7 +13654,6 @@ } ], "license": "MIT", - "peer": true, "dependencies": { "nanoid": "^3.3.11", "picocolors": "^1.1.1", @@ -14571,7 +14557,6 @@ "resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-7.1.1.tgz", "integrity": "sha512-orRsuYpJVw8LdAwqqLykBj9ecS5/cRHlI5+nvTo8LcCKmzDmqVORXtOIYEEQuL9D4BxtA1lm5isAqzQZCoQ6Eg==", "license": "MIT", - "peer": true, "dependencies": { "cssesc": "^3.0.0", "util-deprecate": "^1.0.2" @@ -15384,26 +15369,24 @@ } }, "node_modules/react": { - "version": "19.2.4", - "resolved": "https://registry.npmjs.org/react/-/react-19.2.4.tgz", - "integrity": "sha512-9nfp2hYpCwOjAN+8TZFGhtWEwgvWHXqESH8qT89AT/lWklpLON22Lc8pEtnpsZz7VmawabSU0gCjnj8aC0euHQ==", + "version": "19.2.6", + "resolved": "https://registry.npmjs.org/react/-/react-19.2.6.tgz", + "integrity": "sha512-sfWGGfavi0xr8Pg0sVsyHMAOziVYKgPLNrS7ig+ivMNb3wbCBw3KxtflsGBAwD3gYQlE/AEZsTLgToRrSCjb0Q==", "license": "MIT", - "peer": true, "engines": { "node": ">=0.10.0" } }, "node_modules/react-dom": { - "version": "19.2.4", - "resolved": "https://registry.npmjs.org/react-dom/-/react-dom-19.2.4.tgz", - "integrity": "sha512-AXJdLo8kgMbimY95O2aKQqsz2iWi9jMgKJhRBAxECE4IFxfcazB2LmzloIoibJI3C12IlY20+KFaLv+71bUJeQ==", + "version": "19.2.6", + "resolved": "https://registry.npmjs.org/react-dom/-/react-dom-19.2.6.tgz", + "integrity": "sha512-0prMI+hvBbPjsWnxDLxlCGyM8PN6UuWjEUCYmZhO67xIV9Xasa/r/vDnq+Xyq4Lo27g8QSbO5YzARu0D1Sps3g==", "license": "MIT", - "peer": true, "dependencies": { "scheduler": "^0.27.0" }, "peerDependencies": { - "react": "^19.2.4" + "react": "^19.2.6" } }, "node_modules/react-fast-compare": { @@ -15454,7 +15437,6 @@ "resolved": "https://registry.npmjs.org/@docusaurus/react-loadable/-/react-loadable-6.0.0.tgz", "integrity": "sha512-YMMxTUQV/QFSnbgrP3tjDzLHRg7vsbMn8e9HAa8o/1iXoiomo48b7sk/kkmWEuWNDPJVlKSJRB6Y2fHqdJk+SQ==", "license": "MIT", - "peer": true, "dependencies": { "@types/react": "*" }, @@ -15463,9 +15445,9 @@ } }, "node_modules/react-loadable-ssr-addon-v5-slorber": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/react-loadable-ssr-addon-v5-slorber/-/react-loadable-ssr-addon-v5-slorber-1.0.1.tgz", - "integrity": "sha512-lq3Lyw1lGku8zUEJPDxsNm1AfYHBrO9Y1+olAYwpUJ2IGFBskM0DMKok97A6LWUpHm+o7IvQBOWu9MLenp9Z+A==", + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/react-loadable-ssr-addon-v5-slorber/-/react-loadable-ssr-addon-v5-slorber-1.0.3.tgz", + "integrity": "sha512-GXfh9VLwB5ERaCsU6RULh7tkemeX15aNh6wuMEBtfdyMa7fFG8TXrhXlx1SoEK2Ty/l6XIkzzYIQmyaWW3JgdQ==", "license": "MIT", "dependencies": { "@babel/runtime": "^7.10.3" @@ -15483,7 +15465,6 @@ "resolved": "https://registry.npmjs.org/react-router/-/react-router-5.3.4.tgz", "integrity": "sha512-Ys9K+ppnJah3QuaRiLxk+jDWOR1MekYQrlytiXxC1RyfbdsZkS5pvKAzCCr031xHixZwpnsYNT5xysdFHQaYsA==", "license": "MIT", - "peer": true, "dependencies": { "@babel/runtime": "^7.12.13", "history": "^4.9.0", @@ -15698,9 +15679,9 @@ "license": "MIT" }, "node_modules/regjsparser": { - "version": "0.13.0", - "resolved": "https://registry.npmjs.org/regjsparser/-/regjsparser-0.13.0.tgz", - "integrity": "sha512-NZQZdC5wOE/H3UT28fVGL+ikOZcEzfMGk/c3iN9UGxzWHMa1op7274oyiUVrAG4B2EuFhus8SvkaYnhvW92p9Q==", + "version": "0.13.1", + "resolved": "https://registry.npmjs.org/regjsparser/-/regjsparser-0.13.1.tgz", + "integrity": "sha512-dLsljMd9sqwRkby8zhO1gSg3PnJIBFid8f4CQj/sXx+7cKx+E7u0PKhZ+U4wmhx7EfmtvnA318oVaIkAB1lRJw==", "license": "BSD-2-Clause", "dependencies": { "jsesc": "~3.1.0" @@ -15976,15 +15957,6 @@ "entities": "^2.0.0" } }, - "node_modules/repeat-string": { - "version": "1.6.1", - "resolved": "https://registry.npmjs.org/repeat-string/-/repeat-string-1.6.1.tgz", - "integrity": "sha512-PV0dzCYDNfRi1jCDbJzpW7jNNDRuCOG/jI5ctQcGKt/clZD+YcPS3yIlWuTJMmESC8aevCFmWJy5wjAFgNqN6w==", - "license": "MIT", - "engines": { - "node": ">=0.10" - } - }, "node_modules/require-from-string": { "version": "2.0.2", "resolved": "https://registry.npmjs.org/require-from-string/-/require-from-string-2.0.2.tgz", @@ -16009,11 +15981,12 @@ "license": "MIT" }, "node_modules/resolve": { - "version": "1.22.11", - "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.11.tgz", - "integrity": "sha512-RfqAvLnMl313r7c9oclB1HhUEAezcpLjz95wFH4LVuhk9JF/r22qmVP9AMmOU4vMX7Q8pN8jwNg/CSpdFnMjTQ==", + "version": "1.22.12", + "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.12.tgz", + "integrity": "sha512-TyeJ1zif53BPfHootBGwPRYT1RUt6oGWsaQr8UyZW/eAm9bKoijtvruSDEmZHm92CwS9nj7/fWttqPCgzep8CA==", "license": "MIT", "dependencies": { + "es-errors": "^1.3.0", "is-core-module": "^2.16.1", "path-parse": "^1.0.7", "supports-preserve-symlinks-flag": "^1.0.0" @@ -16163,9 +16136,9 @@ "license": "MIT" }, "node_modules/sax": { - "version": "1.5.0", - "resolved": "https://registry.npmjs.org/sax/-/sax-1.5.0.tgz", - "integrity": "sha512-21IYA3Q5cQf089Z6tgaUTr7lDAyzoTPx5HRtbhsME8Udispad8dC/+sziTNugOEx54ilvatQ9YCzl4KQLPcRHA==", + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/sax/-/sax-1.6.0.tgz", + "integrity": "sha512-6R3J5M4AcbtLUdZmRv2SygeVaM7IhrLXu9BmnOGmmACak8fiUtOsYNWUS4uK7upbmHIBbLBeFeI//477BKLBzA==", "license": "BlueOak-1.0.0", "engines": { "node": ">=11.0.0" @@ -17244,8 +17217,7 @@ "version": "2.8.1", "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.8.1.tgz", "integrity": "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==", - "license": "0BSD", - "peer": true + "license": "0BSD" }, "node_modules/tsyringe": { "version": "4.10.0", @@ -17649,11 +17621,10 @@ } }, "node_modules/url-loader/node_modules/ajv": { - "version": "6.14.0", - "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.14.0.tgz", - "integrity": "sha512-IWrosm/yrn43eiKqkfkHis7QioDleaXQHdDVPKg0FSwwd/DuvyX79TZnFOnYpB7dcsFAMmtFztZuXPDvSePkFw==", + "version": "6.15.0", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.15.0.tgz", + "integrity": "sha512-fgFx7Hfoq60ytK2c7DhnF8jIvzYgOMxfugjLOSMHjLIPgenqa7S7oaagATUq99mV6IYvN2tRmC0wnTYX6iPbMw==", "license": "MIT", - "peer": true, "dependencies": { "fast-deep-equal": "^3.1.1", "fast-json-stable-stringify": "^2.0.0", @@ -17852,7 +17823,6 @@ "resolved": "https://registry.npmjs.org/webpack/-/webpack-5.105.4.tgz", "integrity": "sha512-jTywjboN9aHxFlToqb0K0Zs9SbBoW4zRUlGzI2tYNxVYcEi/IPpn+Xi4ye5jTLvX2YeLuic/IvxNot+Q1jMoOw==", "license": "MIT", - "peer": true, "dependencies": { "@types/eslint-scope": "^3.7.7", "@types/estree": "^1.0.8", @@ -18147,75 +18117,30 @@ } }, "node_modules/webpackbar": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/webpackbar/-/webpackbar-6.0.1.tgz", - "integrity": "sha512-TnErZpmuKdwWBdMoexjio3KKX6ZtoKHRVvLIU0A47R0VVBDtx3ZyOJDktgYixhoJokZTYTt1Z37OkO9pnGJa9Q==", + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/webpackbar/-/webpackbar-7.0.0.tgz", + "integrity": "sha512-aS9soqSO2iCHgqHoCrj4LbfGQUboDCYJPSFOAchEK+9psIjNrfSWW4Y0YEz67MKURNvMmfo0ycOg9d/+OOf9/Q==", "license": "MIT", "dependencies": { - "ansi-escapes": "^4.3.2", - "chalk": "^4.1.2", + "ansis": "^3.2.0", "consola": "^3.2.3", - "figures": "^3.2.0", - "markdown-table": "^2.0.0", "pretty-time": "^1.1.0", - "std-env": "^3.7.0", - "wrap-ansi": "^7.0.0" + "std-env": "^3.7.0" }, "engines": { "node": ">=14.21.3" }, "peerDependencies": { + "@rspack/core": "*", "webpack": "3 || 4 || 5" - } - }, - "node_modules/webpackbar/node_modules/emoji-regex": { - "version": "8.0.0", - "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", - "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", - "license": "MIT" - }, - "node_modules/webpackbar/node_modules/markdown-table": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/markdown-table/-/markdown-table-2.0.0.tgz", - "integrity": "sha512-Ezda85ToJUBhM6WGaG6veasyym+Tbs3cMAw/ZhOPqXiYsr0jgocBV3j3nx+4lk47plLlIqjwuTm/ywVI+zjJ/A==", - "license": "MIT", - "dependencies": { - "repeat-string": "^1.0.0" - }, - "funding": { - "type": "github", - "url": "https://github.com/sponsors/wooorm" - } - }, - "node_modules/webpackbar/node_modules/string-width": { - "version": "4.2.3", - "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", - "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", - "license": "MIT", - "dependencies": { - "emoji-regex": "^8.0.0", - "is-fullwidth-code-point": "^3.0.0", - "strip-ansi": "^6.0.1" }, - "engines": { - "node": ">=8" - } - }, - "node_modules/webpackbar/node_modules/wrap-ansi": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz", - "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==", - "license": "MIT", - "dependencies": { - "ansi-styles": "^4.0.0", - "string-width": "^4.1.0", - "strip-ansi": "^6.0.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/chalk/wrap-ansi?sponsor=1" + "peerDependenciesMeta": { + "@rspack/core": { + "optional": true + }, + "webpack": { + "optional": true + } } }, "node_modules/websocket-driver": { diff --git a/docs/package.json b/docs/package.json index e05da191..fc615fd8 100644 --- a/docs/package.json +++ b/docs/package.json @@ -14,18 +14,18 @@ "write-heading-ids": "docusaurus write-heading-ids" }, "dependencies": { - "@docusaurus/core": "^3.9.2", - "@docusaurus/preset-classic": "^3.9.2", - "@docusaurus/theme-common": "^3.9.2", + "@docusaurus/core": "^3.10.1", + "@docusaurus/preset-classic": "^3.10.1", + "@docusaurus/theme-common": "^3.10.1", "@mdx-js/react": "^3.1.1", "clsx": "^2.1.1", "prism-react-renderer": "^2.4.1", - "react": "^19.2.4", - "react-dom": "^19.2.4" + "react": "^19.2.6", + "react-dom": "^19.2.6" }, "devDependencies": { - "@docusaurus/module-type-aliases": "^3.9.2", - "@docusaurus/types": "^3.9.2" + "@docusaurus/module-type-aliases": "^3.10.1", + "@docusaurus/types": "^3.10.1" }, "browserslist": { "production": [ diff --git a/domain/domain-events/domain-events-api.gradle b/domain/domain-events/domain-events-api.gradle index 7af7f448..b42e4b9e 100644 --- a/domain/domain-events/domain-events-api.gradle +++ b/domain/domain-events/domain-events-api.gradle @@ -5,5 +5,5 @@ ext { dependencies { api 'org.reactivestreams:reactive-streams:1.0.4' - api 'io.cloudevents:cloudevents-api:4.0.1' + api 'io.cloudevents:cloudevents-api:4.0.2' } \ No newline at end of file diff --git a/gradle/wrapper/gradle-wrapper.jar b/gradle/wrapper/gradle-wrapper.jar index d997cfc6..b1b8ef56 100644 Binary files a/gradle/wrapper/gradle-wrapper.jar and b/gradle/wrapper/gradle-wrapper.jar differ diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties index c61a118f..df6a6ad7 100644 --- a/gradle/wrapper/gradle-wrapper.properties +++ b/gradle/wrapper/gradle-wrapper.properties @@ -1,7 +1,9 @@ distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-9.4.1-bin.zip +distributionUrl=https\://services.gradle.org/distributions/gradle-9.5.1-bin.zip networkTimeout=10000 +retries=0 +retryBackOffMs=500 validateDistributionUrl=true zipStoreBase=GRADLE_USER_HOME zipStorePath=wrapper/dists diff --git a/gradlew b/gradlew index 739907df..b9bb139f 100755 --- a/gradlew +++ b/gradlew @@ -57,7 +57,7 @@ # Darwin, MinGW, and NonStop. # # (3) This script is generated from the Groovy template -# https://github.com/gradle/gradle/blob/2d6327017519d23b96af35865dc997fcb544fb40/platforms/jvm/plugins-application/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt +# https://github.com/gradle/gradle/blob/3d91ce3b8caaf77ad09f381f43615b715b53f72c/platforms/jvm/plugins-application/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt # within the Gradle project. # # You can find Gradle at https://github.com/gradle/gradle/. diff --git a/gradlew.bat b/gradlew.bat index e509b2dd..aa5f10b0 100644 --- a/gradlew.bat +++ b/gradlew.bat @@ -23,8 +23,8 @@ @rem @rem ########################################################################## -@rem Set local scope for the variables with windows NT shell -if "%OS%"=="Windows_NT" setlocal +@rem Set local scope for the variables, and ensure extensions are enabled +setlocal EnableExtensions set DIRNAME=%~dp0 if "%DIRNAME%"=="" set DIRNAME=. @@ -51,7 +51,7 @@ echo. 1>&2 echo Please set the JAVA_HOME variable in your environment to match the 1>&2 echo location of your Java installation. 1>&2 -goto fail +"%COMSPEC%" /c exit 1 :findJavaFromJavaHome set JAVA_HOME=%JAVA_HOME:"=% @@ -65,7 +65,7 @@ echo. 1>&2 echo Please set the JAVA_HOME variable in your environment to match the 1>&2 echo location of your Java installation. 1>&2 -goto fail +"%COMSPEC%" /c exit 1 :execute @rem Setup the command line @@ -73,21 +73,10 @@ goto fail @rem Execute Gradle -"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -jar "%APP_HOME%\gradle\wrapper\gradle-wrapper.jar" %* +@rem endlocal doesn't take effect until after the line is parsed and variables are expanded +@rem which allows us to clear the local environment before executing the java command +endlocal & "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -jar "%APP_HOME%\gradle\wrapper\gradle-wrapper.jar" %* & call :exitWithErrorLevel -:end -@rem End local scope for the variables with windows NT shell -if %ERRORLEVEL% equ 0 goto mainEnd - -:fail -rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of -rem the _cmd.exe /c_ return code! -set EXIT_CODE=%ERRORLEVEL% -if %EXIT_CODE% equ 0 set EXIT_CODE=1 -if not ""=="%GRADLE_EXIT_CONSOLE%" exit %EXIT_CODE% -exit /b %EXIT_CODE% - -:mainEnd -if "%OS%"=="Windows_NT" endlocal - -:omega +:exitWithErrorLevel +@rem Use "%COMSPEC%" /c exit to allow operators to work properly in scripts +"%COMSPEC%" /c exit %ERRORLEVEL% diff --git a/main.gradle b/main.gradle index 75310037..9f035687 100644 --- a/main.gradle +++ b/main.gradle @@ -91,7 +91,7 @@ subprojects { dependencyManagement { imports { - mavenBom 'org.springframework.boot:spring-boot-dependencies:4.0.4' + mavenBom 'org.springframework.boot:spring-boot-dependencies:4.0.6' } } @@ -187,6 +187,6 @@ tasks.register('generateMergedReport', JacocoReport) { } tasks.named('wrapper') { - gradleVersion = '9.4.1' + gradleVersion = '9.5.1' validateDistributionUrl = true } \ No newline at end of file diff --git a/samples/async/async-kafka-sender-client/async-kafka-sender-client.gradle b/samples/async/async-kafka-sender-client/async-kafka-sender-client.gradle index d73c3b23..9d3ba7af 100644 --- a/samples/async/async-kafka-sender-client/async-kafka-sender-client.gradle +++ b/samples/async/async-kafka-sender-client/async-kafka-sender-client.gradle @@ -4,7 +4,7 @@ dependencies { implementation project(':shared') implementation project(':async-kafka-starter') implementation project(':cloudevents-json-jackson') - implementation 'io.cloudevents:cloudevents-core:4.0.1' + implementation 'io.cloudevents:cloudevents-core:4.0.2' implementation 'org.springframework.boot:spring-boot-starter-webflux' implementation 'org.springframework.boot:spring-boot-starter-actuator' implementation 'io.micrometer:micrometer-registry-prometheus' diff --git a/samples/async/eda-async-receiver-responder/eda-async-receiver-sample.gradle b/samples/async/eda-async-receiver-responder/eda-async-receiver-sample.gradle index f8e8ef06..c3c59d4c 100644 --- a/samples/async/eda-async-receiver-responder/eda-async-receiver-sample.gradle +++ b/samples/async/eda-async-receiver-responder/eda-async-receiver-sample.gradle @@ -4,5 +4,5 @@ dependencies { implementation project(":shared") implementation project(":async-commons-rabbit-starter") implementation 'org.springframework.boot:spring-boot-starter' - implementation 'io.cloudevents:cloudevents-core:4.0.1' + implementation 'io.cloudevents:cloudevents-core:4.0.2' } \ No newline at end of file diff --git a/samples/async/eda-async-sender-client-domain-a/eda-async-sender-client-domain-a.gradle b/samples/async/eda-async-sender-client-domain-a/eda-async-sender-client-domain-a.gradle index b4fa1123..1c41e0e0 100644 --- a/samples/async/eda-async-sender-client-domain-a/eda-async-sender-client-domain-a.gradle +++ b/samples/async/eda-async-sender-client-domain-a/eda-async-sender-client-domain-a.gradle @@ -6,6 +6,6 @@ dependencies { implementation 'org.springframework.boot:spring-boot-starter-webflux' implementation 'org.springframework.boot:spring-boot-starter-actuator' implementation 'io.micrometer:micrometer-registry-prometheus' - implementation 'io.cloudevents:cloudevents-core:4.0.1' + implementation 'io.cloudevents:cloudevents-core:4.0.2' } \ No newline at end of file diff --git a/samples/async/eda-async-sender-client/eda-async-sender-client.gradle b/samples/async/eda-async-sender-client/eda-async-sender-client.gradle index b4fa1123..1c41e0e0 100644 --- a/samples/async/eda-async-sender-client/eda-async-sender-client.gradle +++ b/samples/async/eda-async-sender-client/eda-async-sender-client.gradle @@ -6,6 +6,6 @@ dependencies { implementation 'org.springframework.boot:spring-boot-starter-webflux' implementation 'org.springframework.boot:spring-boot-starter-actuator' implementation 'io.micrometer:micrometer-registry-prometheus' - implementation 'io.cloudevents:cloudevents-core:4.0.1' + implementation 'io.cloudevents:cloudevents-core:4.0.2' } \ No newline at end of file diff --git a/starters/async-commons-starter/src/main/java/org/reactivecommons/async/starter/props/GenericAsyncPropsDomain.java b/starters/async-commons-starter/src/main/java/org/reactivecommons/async/starter/props/GenericAsyncPropsDomain.java index a0c21f5d..b4e6464a 100644 --- a/starters/async-commons-starter/src/main/java/org/reactivecommons/async/starter/props/GenericAsyncPropsDomain.java +++ b/starters/async-commons-starter/src/main/java/org/reactivecommons/async/starter/props/GenericAsyncPropsDomain.java @@ -147,6 +147,7 @@ private static X instantiate(Class xClass, Map arg) { } + @Deprecated(forRemoval = true, since = "7.2.0") public interface SecretFiller

{ void fillWithSecret(String domain, GenericAsyncProps

props); } diff --git a/starters/async-kafka-starter/src/main/java/org/reactivecommons/async/kafka/config/props/AsyncKafkaPropsDomain.java b/starters/async-kafka-starter/src/main/java/org/reactivecommons/async/kafka/config/props/AsyncKafkaPropsDomain.java index ea9f9496..db676261 100644 --- a/starters/async-kafka-starter/src/main/java/org/reactivecommons/async/kafka/config/props/AsyncKafkaPropsDomain.java +++ b/starters/async-kafka-starter/src/main/java/org/reactivecommons/async/kafka/config/props/AsyncKafkaPropsDomain.java @@ -3,16 +3,32 @@ import lombok.Getter; import lombok.Setter; import org.reactivecommons.async.kafka.config.KafkaProperties; +import org.reactivecommons.async.starter.exceptions.InvalidConfigurationException; import org.reactivecommons.async.starter.props.GenericAsyncPropsDomain; +import org.springframework.beans.factory.ObjectProvider; +import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Value; import java.lang.reflect.Constructor; +import static org.reactivecommons.async.api.HandlerRegistry.DEFAULT_DOMAIN; + @Getter @Setter public class AsyncKafkaPropsDomain extends GenericAsyncPropsDomain { + @Autowired public AsyncKafkaPropsDomain(@Value("${spring.application.name}") String defaultAppName, + KafkaProperties defaultKafkaProperties, + AsyncKafkaPropsDomainProperties configured, + KafkaSecretFiller kafkaSecretFiller, + ObjectProvider customizer) { + super(defaultAppName, defaultKafkaProperties, + applyCustomizer(configured, customizer.getIfAvailable()), + kafkaSecretFiller, AsyncKafkaProps.class, KafkaProperties.class); + } + + public AsyncKafkaPropsDomain(String defaultAppName, KafkaProperties defaultKafkaProperties, AsyncKafkaPropsDomainProperties configured, KafkaSecretFiller kafkaSecretFiller) { @@ -20,15 +36,47 @@ public AsyncKafkaPropsDomain(@Value("${spring.application.name}") String default KafkaProperties.class); } - @SuppressWarnings("unchecked") public static AsyncPropsDomainBuilder builder() { - return GenericAsyncPropsDomain.builder(KafkaProperties.class, - AsyncKafkaPropsDomainProperties.class, - (Constructor) AsyncKafkaPropsDomain.class.getDeclaredConstructors()[0]); + try { + Constructor ctor = AsyncKafkaPropsDomain.class.getDeclaredConstructor( + String.class, KafkaProperties.class, AsyncKafkaPropsDomainProperties.class, + KafkaSecretFiller.class); + return GenericAsyncPropsDomain.builder(KafkaProperties.class, + AsyncKafkaPropsDomainProperties.class, ctor); + } catch (NoSuchMethodException e) { + throw new IllegalStateException("Constructor not found", e); + } } + private static AsyncKafkaPropsDomainProperties applyCustomizer( + AsyncKafkaPropsDomainProperties configured, KafkaPropsCustomizer customizer) { + if (customizer != null) { + customizer.customize(configured); + if (!configured.containsKey(DEFAULT_DOMAIN)) { + throw new InvalidConfigurationException(""" + KafkaPropsCustomizer was applied but the default domain 'app' is not defined. \ + When using KafkaPropsCustomizer, you must declare the 'app' domain in your \ + application.yaml (reactive.commons.kafka.app.*), or add the 'app' domain (or any other new domain) \ + directly inside the customizer using \ + domainProperties.put("app", AsyncKafkaProps.builder()...build())."""); + } + } + return configured; + } + + @Deprecated(forRemoval = true, since = "7.2.0") public interface KafkaSecretFiller extends GenericAsyncPropsDomain.SecretFiller { } + /** + * Customizer interface for Kafka async properties. + * Allows programmatic modification of properties loaded from YAML configuration. + * Properties modified through this customizer take precedence over YAML values. + */ + @FunctionalInterface + public interface KafkaPropsCustomizer { + void customize(AsyncKafkaPropsDomainProperties domainProperties); + } + } diff --git a/starters/async-kafka-starter/src/test/java/org/reactivecommons/async/kafka/config/props/AsyncKafkaPropsDomainCustomizerTest.java b/starters/async-kafka-starter/src/test/java/org/reactivecommons/async/kafka/config/props/AsyncKafkaPropsDomainCustomizerTest.java new file mode 100644 index 00000000..36da54d3 --- /dev/null +++ b/starters/async-kafka-starter/src/test/java/org/reactivecommons/async/kafka/config/props/AsyncKafkaPropsDomainCustomizerTest.java @@ -0,0 +1,161 @@ +package org.reactivecommons.async.kafka.config.props; + +import org.junit.jupiter.api.Test; +import org.reactivecommons.async.kafka.config.KafkaProperties; +import org.springframework.beans.factory.ObjectProvider; + +import java.util.List; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.when; +import static org.reactivecommons.async.api.HandlerRegistry.DEFAULT_DOMAIN; + +class AsyncKafkaPropsDomainCustomizerTest { + + @Test + void shouldMergeCustomizerWithYamlProperties() { + // Arrange - simulate YAML-loaded properties + AsyncKafkaPropsDomainProperties yamlProps = new AsyncKafkaPropsDomainProperties(); + AsyncKafkaProps appProps = AsyncKafkaProps.builder() + .withDLQRetry(false) + .maxRetries(3) + .retryDelay(10000) + .checkExistingTopics(true) + .build(); + yamlProps.put(DEFAULT_DOMAIN, appProps); + + KafkaProperties defaultKafkaProperties = new KafkaProperties(); + defaultKafkaProperties.setBootstrapServers(List.of("localhost:9092")); + + // Arrange - customizer that overrides specific properties + KafkaProperties customConnProps = new KafkaProperties(); + customConnProps.setBootstrapServers(List.of("custom-host:9093")); + + AsyncKafkaPropsDomain.KafkaPropsCustomizer customizer = domainProperties -> { + AsyncKafkaProps props = domainProperties.get(DEFAULT_DOMAIN); + if (props != null) { + props.setConnectionProperties(customConnProps); + props.setRetryDelay(500000); + } + }; + + @SuppressWarnings("unchecked") + ObjectProvider customizerProvider = mock(ObjectProvider.class); + when(customizerProvider.getIfAvailable()).thenReturn(customizer); + + AsyncKafkaPropsDomain.KafkaSecretFiller secretFiller = (domain, props) -> { + }; + + // Act + AsyncKafkaPropsDomain propsDomain = new AsyncKafkaPropsDomain( + "test-app", defaultKafkaProperties, yamlProps, secretFiller, customizerProvider); + + // Assert - customizer values take precedence + AsyncKafkaProps result = propsDomain.getProps(DEFAULT_DOMAIN); + assertThat(result.getRetryDelay()).isEqualTo(500000); + assertThat(result.getConnectionProperties().getBootstrapServers()).containsExactly("custom-host:9093"); + + // Assert - YAML values are preserved for non-customized properties + assertThat(result.getWithDLQRetry()).isFalse(); + assertThat(result.getMaxRetries()).isEqualTo(3); + assertThat(result.getCheckExistingTopics()).isTrue(); + } + + @Test + void shouldWorkWithoutCustomizer() { + // Arrange + AsyncKafkaPropsDomainProperties yamlProps = new AsyncKafkaPropsDomainProperties(); + AsyncKafkaProps appProps = AsyncKafkaProps.builder() + .maxRetries(5) + .retryDelay(2000) + .build(); + yamlProps.put(DEFAULT_DOMAIN, appProps); + + KafkaProperties defaultKafkaProperties = new KafkaProperties(); + + @SuppressWarnings("unchecked") + ObjectProvider customizerProvider = mock(ObjectProvider.class); + when(customizerProvider.getIfAvailable()).thenReturn(null); + + AsyncKafkaPropsDomain.KafkaSecretFiller secretFiller = (domain, props) -> { + }; + + // Act + AsyncKafkaPropsDomain propsDomain = new AsyncKafkaPropsDomain( + "test-app", defaultKafkaProperties, yamlProps, secretFiller, customizerProvider); + + // Assert - YAML values are preserved + AsyncKafkaProps result = propsDomain.getProps(DEFAULT_DOMAIN); + assertThat(result.getMaxRetries()).isEqualTo(5); + assertThat(result.getRetryDelay()).isEqualTo(2000); + } + + @Test + void shouldAllowCustomizerToAddNewDomains() { + // Arrange - YAML has only default domain + AsyncKafkaPropsDomainProperties yamlProps = new AsyncKafkaPropsDomainProperties(); + AsyncKafkaProps appProps = AsyncKafkaProps.builder() + .maxRetries(3) + .build(); + yamlProps.put(DEFAULT_DOMAIN, appProps); + + KafkaProperties defaultKafkaProperties = new KafkaProperties(); + defaultKafkaProperties.setBootstrapServers(List.of("localhost:9092")); + + KafkaProperties accountsConnProps = new KafkaProperties(); + accountsConnProps.setBootstrapServers(List.of("accounts-host:9093")); + + // Customizer adds a new domain + AsyncKafkaPropsDomain.KafkaPropsCustomizer customizer = domainProperties -> { + AsyncKafkaProps accountsProps = AsyncKafkaProps.builder() + .connectionProperties(accountsConnProps) + .maxRetries(10) + .build(); + domainProperties.put("accounts", accountsProps); + }; + + @SuppressWarnings("unchecked") + ObjectProvider customizerProvider = mock(ObjectProvider.class); + when(customizerProvider.getIfAvailable()).thenReturn(customizer); + + AsyncKafkaPropsDomain.KafkaSecretFiller secretFiller = (domain, props) -> { + }; + + // Act + AsyncKafkaPropsDomain propsDomain = new AsyncKafkaPropsDomain( + "test-app", defaultKafkaProperties, yamlProps, secretFiller, customizerProvider); + + // Assert - original domain is preserved + AsyncKafkaProps appResult = propsDomain.getProps(DEFAULT_DOMAIN); + assertThat(appResult.getMaxRetries()).isEqualTo(3); + + // Assert - new domain was added by customizer + AsyncKafkaProps accountsResult = propsDomain.getProps("accounts"); + assertThat(accountsResult.getConnectionProperties().getBootstrapServers()).containsExactly("accounts-host:9093"); + assertThat(accountsResult.getMaxRetries()).isEqualTo(10); + } + + @Test + void shouldWorkWithFourParamConstructor() { + // Arrange - backward compatibility + AsyncKafkaPropsDomainProperties yamlProps = new AsyncKafkaPropsDomainProperties(); + AsyncKafkaProps appProps = AsyncKafkaProps.builder() + .maxRetries(7) + .build(); + yamlProps.put(DEFAULT_DOMAIN, appProps); + + KafkaProperties defaultKafkaProperties = new KafkaProperties(); + + AsyncKafkaPropsDomain.KafkaSecretFiller secretFiller = (domain, props) -> { + }; + + // Act - uses 4-param constructor (no customizer) + AsyncKafkaPropsDomain propsDomain = new AsyncKafkaPropsDomain( + "test-app", defaultKafkaProperties, yamlProps, secretFiller); + + // Assert + AsyncKafkaProps result = propsDomain.getProps(DEFAULT_DOMAIN); + assertThat(result.getMaxRetries()).isEqualTo(7); + } +} diff --git a/starters/async-rabbit-starter/src/main/java/org/reactivecommons/async/rabbit/config/props/AsyncPropsDomain.java b/starters/async-rabbit-starter/src/main/java/org/reactivecommons/async/rabbit/config/props/AsyncPropsDomain.java index d72aaff8..54c02677 100644 --- a/starters/async-rabbit-starter/src/main/java/org/reactivecommons/async/rabbit/config/props/AsyncPropsDomain.java +++ b/starters/async-rabbit-starter/src/main/java/org/reactivecommons/async/rabbit/config/props/AsyncPropsDomain.java @@ -3,15 +3,32 @@ import lombok.Getter; import lombok.Setter; import org.reactivecommons.async.rabbit.config.RabbitProperties; +import org.reactivecommons.async.starter.exceptions.InvalidConfigurationException; import org.reactivecommons.async.starter.props.GenericAsyncPropsDomain; +import org.springframework.beans.factory.ObjectProvider; +import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Value; import java.lang.reflect.Constructor; +import static org.reactivecommons.async.api.HandlerRegistry.DEFAULT_DOMAIN; + @Getter @Setter public class AsyncPropsDomain extends GenericAsyncPropsDomain { + + @Autowired public AsyncPropsDomain(@Value("${spring.application.name}") String defaultAppName, + RabbitProperties defaultRabbitProperties, + AsyncRabbitPropsDomainProperties configured, + RabbitSecretFiller secretFiller, + ObjectProvider customizer) { + super(defaultAppName, defaultRabbitProperties, + applyCustomizer(configured, customizer.getIfAvailable()), + secretFiller, AsyncProps.class, RabbitProperties.class); + } + + public AsyncPropsDomain(String defaultAppName, RabbitProperties defaultRabbitProperties, AsyncRabbitPropsDomainProperties configured, RabbitSecretFiller secretFiller) { @@ -19,12 +36,17 @@ public AsyncPropsDomain(@Value("${spring.application.name}") String defaultAppNa RabbitProperties.class); } - @SuppressWarnings("unchecked") public static AsyncPropsDomainBuilder builder() { - return GenericAsyncPropsDomain.builder(RabbitProperties.class, - AsyncRabbitPropsDomainProperties.class, - (Constructor) AsyncPropsDomain.class.getDeclaredConstructors()[0]); + try { + Constructor ctor = AsyncPropsDomain.class.getDeclaredConstructor( + String.class, RabbitProperties.class, AsyncRabbitPropsDomainProperties.class, + RabbitSecretFiller.class); + return GenericAsyncPropsDomain.builder(RabbitProperties.class, + AsyncRabbitPropsDomainProperties.class, ctor); + } catch (NoSuchMethodException e) { + throw new IllegalStateException("Constructor not found", e); + } } @Override @@ -34,7 +56,34 @@ protected void fillCustoms(AsyncProps asyncProps) { } } + private static AsyncRabbitPropsDomainProperties applyCustomizer( + AsyncRabbitPropsDomainProperties configured, RabbitPropsCustomizer customizer) { + if (customizer != null) { + customizer.customize(configured); + if (!configured.containsKey(DEFAULT_DOMAIN)) { + throw new InvalidConfigurationException(""" + RabbitPropsCustomizer was applied but the default domain 'app' is not defined. \ + When using RabbitPropsCustomizer, you must declare the 'app' domain in your \ + application.yaml (app.async.app.*), or add the 'app' domain (or any other new domain) \ + directly inside the customizer using \ + domainProperties.put("app", AsyncProps.builder()...build())."""); + } + } + return configured; + } + + @Deprecated(forRemoval = true, since = "7.2.0") public interface RabbitSecretFiller extends SecretFiller { } + /** + * Customizer interface for RabbitMQ async properties. + * Allows programmatic modification of properties loaded from YAML configuration. + * Properties modified through this customizer take precedence over YAML values. + */ + @FunctionalInterface + public interface RabbitPropsCustomizer { + void customize(AsyncRabbitPropsDomainProperties domainProperties); + } + } diff --git a/starters/async-rabbit-starter/src/test/java/org/reactivecommons/async/rabbit/config/props/AsyncPropsDomainCustomizerTest.java b/starters/async-rabbit-starter/src/test/java/org/reactivecommons/async/rabbit/config/props/AsyncPropsDomainCustomizerTest.java new file mode 100644 index 00000000..c229efd2 --- /dev/null +++ b/starters/async-rabbit-starter/src/test/java/org/reactivecommons/async/rabbit/config/props/AsyncPropsDomainCustomizerTest.java @@ -0,0 +1,240 @@ +package org.reactivecommons.async.rabbit.config.props; + +import org.junit.jupiter.api.Test; +import org.reactivecommons.async.rabbit.config.RabbitProperties; +import org.springframework.beans.factory.ObjectProvider; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.when; +import static org.reactivecommons.async.api.HandlerRegistry.DEFAULT_DOMAIN; + +class AsyncPropsDomainCustomizerTest { + + @SuppressWarnings("unchecked") + private ObjectProvider customizerProviderOf( + AsyncPropsDomain.RabbitPropsCustomizer customizer) { + ObjectProvider customizerProvider = mock(ObjectProvider.class); + when(customizerProvider.getIfAvailable()).thenReturn(customizer); + return customizerProvider; + } + + @Test + void shouldMergeCustomizerWithYamlProperties() { + // Arrange - simulate YAML-loaded properties + AsyncRabbitPropsDomainProperties yamlProps = new AsyncRabbitPropsDomainProperties(); + AsyncProps appProps = AsyncProps.builder() + .withDLQRetry(false) + .maxRetries(3) + .retryDelay(10000) + .listenReplies(false) + .build(); + yamlProps.put(DEFAULT_DOMAIN, appProps); + + RabbitProperties defaultRabbitProperties = new RabbitProperties(); + defaultRabbitProperties.setHost("localhost"); + defaultRabbitProperties.setPort(5672); + + // Arrange - customizer that overrides specific properties + RabbitProperties customConnProps = new RabbitProperties(); + customConnProps.setHost("custom-host"); + customConnProps.setPort(5673); + + AsyncPropsDomain.RabbitPropsCustomizer customizer = domainProperties -> { + AsyncProps props = domainProperties.get(DEFAULT_DOMAIN); + if (props != null) { + props.setConnectionProperties(customConnProps); + props.setRetryDelay(500000); + } + }; + + AsyncPropsDomain.RabbitSecretFiller secretFiller = (domain, props) -> { + }; + + // Act + AsyncPropsDomain propsDomain = new AsyncPropsDomain( + "test-app", defaultRabbitProperties, yamlProps, secretFiller, customizerProviderOf(customizer)); + + // Assert - customizer values take precedence + AsyncProps result = propsDomain.getProps(DEFAULT_DOMAIN); + assertThat(result.getRetryDelay()).isEqualTo(500000); + assertThat(result.getConnectionProperties().getHost()).isEqualTo("custom-host"); + assertThat(result.getConnectionProperties().getPort()).isEqualTo(5673); + + // Assert - YAML values are preserved for non-customized properties + assertThat(result.getWithDLQRetry()).isFalse(); + assertThat(result.getMaxRetries()).isEqualTo(3); + assertThat(result.getListenReplies()).isFalse(); + } + + @Test + void shouldWorkWithoutCustomizer() { + // Arrange - simulate YAML-loaded properties + AsyncRabbitPropsDomainProperties yamlProps = new AsyncRabbitPropsDomainProperties(); + AsyncProps appProps = AsyncProps.builder() + .maxRetries(5) + .retryDelay(2000) + .listenReplies(true) + .build(); + yamlProps.put(DEFAULT_DOMAIN, appProps); + + RabbitProperties defaultRabbitProperties = new RabbitProperties(); + + AsyncPropsDomain.RabbitSecretFiller secretFiller = (domain, props) -> { + }; + + // Act + AsyncPropsDomain propsDomain = new AsyncPropsDomain( + "test-app", defaultRabbitProperties, yamlProps, secretFiller, customizerProviderOf(null)); + + // Assert - YAML values are preserved + AsyncProps result = propsDomain.getProps(DEFAULT_DOMAIN); + assertThat(result.getMaxRetries()).isEqualTo(5); + assertThat(result.getRetryDelay()).isEqualTo(2000); + assertThat(result.getListenReplies()).isTrue(); + } + + @Test + void shouldAllowCustomizerToAddNewDomains() { + // Arrange - YAML has only default domain + AsyncRabbitPropsDomainProperties yamlProps = new AsyncRabbitPropsDomainProperties(); + AsyncProps appProps = AsyncProps.builder() + .maxRetries(3) + .listenReplies(true) + .build(); + yamlProps.put(DEFAULT_DOMAIN, appProps); + + RabbitProperties defaultRabbitProperties = new RabbitProperties(); + defaultRabbitProperties.setHost("localhost"); + + RabbitProperties accountsConnProps = new RabbitProperties(); + accountsConnProps.setHost("accounts-host"); + accountsConnProps.setPort(5673); + + // Customizer adds a new domain + AsyncPropsDomain.RabbitPropsCustomizer customizer = domainProperties -> { + AsyncProps accountsProps = AsyncProps.builder() + .connectionProperties(accountsConnProps) + .maxRetries(10) + .listenReplies(false) + .build(); + domainProperties.put("accounts", accountsProps); + }; + + AsyncPropsDomain.RabbitSecretFiller secretFiller = (domain, props) -> { + }; + + // Act + AsyncPropsDomain propsDomain = new AsyncPropsDomain( + "test-app", defaultRabbitProperties, yamlProps, secretFiller, customizerProviderOf(customizer)); + + // Assert - original domain is preserved + AsyncProps appResult = propsDomain.getProps(DEFAULT_DOMAIN); + assertThat(appResult.getMaxRetries()).isEqualTo(3); + + // Assert - new domain was added by customizer + AsyncProps accountsResult = propsDomain.getProps("accounts"); + assertThat(accountsResult.getConnectionProperties().getHost()).isEqualTo("accounts-host"); + assertThat(accountsResult.getMaxRetries()).isEqualTo(10); + } + + @Test + void shouldCustomizeMultipleYamlDefinedDomains() { + // Arrange - simulate YAML with two custom domains + AsyncRabbitPropsDomainProperties yamlProps = new AsyncRabbitPropsDomainProperties(); + AsyncProps appProps = AsyncProps.builder() + .withDLQRetry(true) + .maxRetries(2) + .listenReplies(false) + .build(); + yamlProps.put(DEFAULT_DOMAIN, appProps); + + AsyncProps accountsProps = AsyncProps.builder() + .listenReplies(false) + .build(); + RabbitProperties accountsConnProps = new RabbitProperties(); + accountsConnProps.setHost("localhost"); + accountsConnProps.setPort(5673); + accountsConnProps.setUsername("guest"); + accountsConnProps.setPassword("guest"); + accountsProps.setConnectionProperties(accountsConnProps); + yamlProps.put("accounts", accountsProps); + + RabbitProperties defaultRabbitProperties = new RabbitProperties(); + defaultRabbitProperties.setHost("localhost"); + defaultRabbitProperties.setPort(5672); + + // Arrange - customizer overrides connection properties on both domains + RabbitProperties customConnProps = new RabbitProperties(); + customConnProps.setHost("custom-rabbit-host"); + customConnProps.setPort(5671); + customConnProps.setUsername("admin"); + customConnProps.setPassword("secret"); + + AsyncPropsDomain.RabbitPropsCustomizer customizer = domainProperties -> { + AsyncProps push = domainProperties.get(DEFAULT_DOMAIN); + if (push != null) { + push.setConnectionProperties(customConnProps); + push.setListenReplies(true); + push.setMaxRetries(3); + } + AsyncProps accounts = domainProperties.get("accounts"); + if (accounts != null) { + accounts.setConnectionProperties(customConnProps); + accounts.setListenReplies(true); + accounts.setMaxRetries(3); + } + }; + + AsyncPropsDomain.RabbitSecretFiller secretFiller = (domain, props) -> { + }; + + // Act + AsyncPropsDomain propsDomain = new AsyncPropsDomain( + "ms_sender", defaultRabbitProperties, yamlProps, secretFiller, customizerProviderOf(customizer)); + + // Assert - app domain: customizer values take precedence + AsyncProps appResult = propsDomain.getProps(DEFAULT_DOMAIN); + assertThat(appResult.getConnectionProperties().getHost()).isEqualTo("custom-rabbit-host"); + assertThat(appResult.getConnectionProperties().getPort()).isEqualTo(5671); + assertThat(appResult.getListenReplies()).isTrue(); + assertThat(appResult.getMaxRetries()).isEqualTo(3); + // YAML values preserved for non-customized properties + assertThat(appResult.getWithDLQRetry()).isTrue(); + + // Assert - accounts domain: customizer values take precedence + AsyncProps accountsResult = propsDomain.getProps("accounts"); + assertThat(accountsResult.getConnectionProperties().getHost()).isEqualTo("custom-rabbit-host"); + assertThat(accountsResult.getConnectionProperties().getPort()).isEqualTo(5671); + assertThat(accountsResult.getListenReplies()).isTrue(); + assertThat(accountsResult.getMaxRetries()).isEqualTo(3); + + // Assert - both domains have the app name set + assertThat(appResult.getAppName()).isEqualTo("ms_sender"); + assertThat(accountsResult.getAppName()).isEqualTo("ms_sender"); + } + + @Test + void shouldWorkWithFourParamConstructor() { + // Arrange - backward compatibility + AsyncRabbitPropsDomainProperties yamlProps = new AsyncRabbitPropsDomainProperties(); + AsyncProps appProps = AsyncProps.builder() + .maxRetries(7) + .listenReplies(true) + .build(); + yamlProps.put(DEFAULT_DOMAIN, appProps); + + RabbitProperties defaultRabbitProperties = new RabbitProperties(); + + AsyncPropsDomain.RabbitSecretFiller secretFiller = (domain, props) -> { + }; + + // Act - uses 4-param constructor (no customizer) + AsyncPropsDomain propsDomain = new AsyncPropsDomain( + "test-app", defaultRabbitProperties, yamlProps, secretFiller); + + // Assert + AsyncProps result = propsDomain.getProps(DEFAULT_DOMAIN); + assertThat(result.getMaxRetries()).isEqualTo(7); + } +} \ No newline at end of file