diff --git a/.dev/dev_arm64.yaml b/.dev/dev_arm64.yaml index 220140d3d..dc1a8726e 100644 --- a/.dev/dev_arm64.yaml +++ b/.dev/dev_arm64.yaml @@ -32,7 +32,7 @@ services: KAFKA_CLUSTERS_0_AUDIT_CONSOLEAUDITENABLED: 'true' kafka0: - image: confluentinc/cp-kafka:7.6.0.arm64 + image: confluentinc/cp-kafka:7.8.0.arm64 user: "0:0" hostname: kafka0 container_name: kafka0 @@ -60,7 +60,7 @@ services: CLUSTER_ID: 'MkU3OEVBNTcwNTJENDM2Qk' schema-registry0: - image: confluentinc/cp-schema-registry:7.6.0.arm64 + image: confluentinc/cp-schema-registry:7.8.0.arm64 ports: - 8085:8085 depends_on: @@ -76,7 +76,7 @@ services: SCHEMA_REGISTRY_KAFKASTORE_TOPIC: _schemas kafka-connect0: - image: confluentinc/cp-kafka-connect:7.6.0.arm64 + image: confluentinc/cp-kafka-connect:7.8.0.arm64 ports: - 8083:8083 depends_on: @@ -101,7 +101,7 @@ services: CONNECT_PLUGIN_PATH: "/usr/share/java,/usr/share/confluent-hub-components,/usr/local/share/kafka/plugins,/usr/share/filestream-connectors" ksqldb0: - image: confluentinc/cp-ksqldb-server:7.6.0.arm64 + image: confluentinc/cp-ksqldb-server:7.8.0.arm64 depends_on: - kafka0 - kafka-connect0 @@ -119,7 +119,7 @@ services: KSQL_CACHE_MAX_BYTES_BUFFERING: 0 kafka-init-topics: - image: confluentinc/cp-kafka:7.6.0.arm64 + image: confluentinc/cp-kafka:7.8.0.arm64 volumes: - ../documentation/compose/data/message.json:/data/message.json depends_on: diff --git a/.gitignore b/.gitignore index efd6a9749..51efbef39 100644 --- a/.gitignore +++ b/.gitignore @@ -42,3 +42,4 @@ build/ *.tgz /docker/*.override.yaml +/e2e-tests/allure-results/ diff --git a/.java-version b/.java-version new file mode 100644 index 000000000..aabe6ec39 --- /dev/null +++ b/.java-version @@ -0,0 +1 @@ +21 diff --git a/README.md b/README.md index 9b6eb8e80..d6206100a 100644 --- a/README.md +++ b/README.md @@ -18,7 +18,6 @@ Versatile, fast and lightweight web UI for managing Apache Kafka® clusters. Quick StartCommunity
- AWS MarketplaceProductHunt

@@ -28,7 +27,7 @@ Versatile, fast and lightweight web UI for managing Apache Kafka® clusters. #### Kafbat UI is a free, open-source web UI to monitor and manage Apache Kafka clusters. -Kafbat UI is a simple tool that makes your data flows observable, helps find and troubleshoot issues faster and deliver optimal performance. Its lightweight dashboard makes it easy to track key metrics of your Kafka clusters - Brokers, Topics, Partitions, Production, and Consumption. +[Kafbat UI](https://kafbat.io/) is a simple tool that makes your data flows observable, helps find and troubleshoot issues faster and deliver optimal performance. Its lightweight dashboard makes it easy to track key metrics of your Kafka clusters - Brokers, Topics, Partitions, Production, and Consumption. Kafbat UI, developed by Kafbat*, proudly carries forward the legacy of the UI Apache Kafka project. diff --git a/api/pom.xml b/api/pom.xml index 3f7c044d0..dc774c09a 100644 --- a/api/pom.xml +++ b/api/pom.xml @@ -50,7 +50,10 @@ org.apache.kafka kafka-clients - ${kafka-clients.version} + + ${confluent.version}-ccs org.apache.commons diff --git a/api/src/main/java/io/kafbat/ui/client/RetryingKafkaConnectClient.java b/api/src/main/java/io/kafbat/ui/client/RetryingKafkaConnectClient.java index 72ab7386a..474a0c159 100644 --- a/api/src/main/java/io/kafbat/ui/client/RetryingKafkaConnectClient.java +++ b/api/src/main/java/io/kafbat/ui/client/RetryingKafkaConnectClient.java @@ -22,6 +22,7 @@ import java.util.Objects; import javax.annotation.Nullable; import lombok.extern.slf4j.Slf4j; +import org.apache.commons.lang3.StringUtils; import org.springframework.http.ResponseEntity; import org.springframework.util.unit.DataSize; import org.springframework.web.client.RestClientException; @@ -51,14 +52,36 @@ private static Retry conflictCodeRetry() { (WebClientResponseException.Conflict) signal.failure())); } - private static Mono withRetryOnConflict(Mono publisher) { - return publisher.retryWhen(conflictCodeRetry()); + private static @NotNull Retry retryOnRebalance() { + return Retry.fixedDelay(MAX_RETRIES, RETRIES_DELAY).filter(e -> { + + if (e instanceof WebClientResponseException.InternalServerError exception) { + final var errorMessage = getMessage(exception); + return StringUtils.equals(errorMessage, + // From https://github.com/apache/kafka/blob/dfc07e0e0c6e737a56a5402644265f634402b864/connect/runtime/src/main/java/org/apache/kafka/connect/runtime/distributed/DistributedHerder.java#L2340 + "Request cannot be completed because a rebalance is expected"); + } + return false; + }); + } + + private static Mono withRetryOnConflictOrRebalance(Mono publisher) { + return publisher + .retryWhen(retryOnRebalance()) + .retryWhen(conflictCodeRetry()); + } + + private static Flux withRetryOnConflictOrRebalance(Flux publisher) { + return publisher + .retryWhen(retryOnRebalance()) + .retryWhen(conflictCodeRetry()); } - private static Flux withRetryOnConflict(Flux publisher) { - return publisher.retryWhen(conflictCodeRetry()); + private static Mono withRetryOnRebalance(Mono publisher) { + return publisher.retryWhen(retryOnRebalance()); } + private static Mono withBadRequestErrorHandling(Mono publisher) { return publisher .onErrorResume(WebClientResponseException.BadRequest.class, @@ -73,18 +96,21 @@ private record ErrorMessage(@NotNull @JsonProperty("message") String message) { } private static @NotNull Mono parseConnectErrorMessage(WebClientResponseException parseException) { + return Mono.error(new ValidationException(getMessage(parseException))); + } + + private static String getMessage(WebClientResponseException parseException) { final var errorMessage = parseException.getResponseBodyAs(ErrorMessage.class); - return Mono.error(new ValidationException( - Objects.requireNonNull(errorMessage, - // see https://github.com/apache/kafka/blob/a0a501952b6d61f6f273bdb8f842346b51e9dfce/connect/runtime/src/main/java/org/apache/kafka/connect/runtime/rest/errors/ConnectExceptionMapper.java - "This should not happen according to the ConnectExceptionMapper") - .message())); + return Objects.requireNonNull(errorMessage, + // see https://github.com/apache/kafka/blob/a0a501952b6d61f6f273bdb8f842346b51e9dfce/connect/runtime/src/main/java/org/apache/kafka/connect/runtime/rest/errors/ConnectExceptionMapper.java + "This should not happen according to the ConnectExceptionMapper") + .message(); } @Override public Mono createConnector(NewConnector newConnector) throws RestClientException { return withBadRequestErrorHandling( - super.createConnector(newConnector) + withRetryOnRebalance(super.createConnector(newConnector)) ); } @@ -92,178 +118,178 @@ public Mono createConnector(NewConnector newConnector) throws RestCli public Mono setConnectorConfig(String connectorName, Map requestBody) throws RestClientException { return withBadRequestErrorHandling( - super.setConnectorConfig(connectorName, requestBody) + withRetryOnRebalance(super.setConnectorConfig(connectorName, requestBody)) ); } @Override public Mono> createConnectorWithHttpInfo(NewConnector newConnector) throws WebClientResponseException { - return withRetryOnConflict(super.createConnectorWithHttpInfo(newConnector)); + return withRetryOnConflictOrRebalance(super.createConnectorWithHttpInfo(newConnector)); } @Override public Mono deleteConnector(String connectorName) throws WebClientResponseException { - return withRetryOnConflict(super.deleteConnector(connectorName)); + return withRetryOnConflictOrRebalance(super.deleteConnector(connectorName)); } @Override public Mono> deleteConnectorWithHttpInfo(String connectorName) throws WebClientResponseException { - return withRetryOnConflict(super.deleteConnectorWithHttpInfo(connectorName)); + return withRetryOnConflictOrRebalance(super.deleteConnectorWithHttpInfo(connectorName)); } @Override public Mono getConnector(String connectorName) throws WebClientResponseException { - return withRetryOnConflict(super.getConnector(connectorName)); + return withRetryOnConflictOrRebalance(super.getConnector(connectorName)); } @Override public Mono> getConnectorWithHttpInfo(String connectorName) throws WebClientResponseException { - return withRetryOnConflict(super.getConnectorWithHttpInfo(connectorName)); + return withRetryOnConflictOrRebalance(super.getConnectorWithHttpInfo(connectorName)); } @Override public Mono> getConnectorConfig(String connectorName) throws WebClientResponseException { - return withRetryOnConflict(super.getConnectorConfig(connectorName)); + return withRetryOnConflictOrRebalance(super.getConnectorConfig(connectorName)); } @Override public Mono>> getConnectorConfigWithHttpInfo(String connectorName) throws WebClientResponseException { - return withRetryOnConflict(super.getConnectorConfigWithHttpInfo(connectorName)); + return withRetryOnConflictOrRebalance(super.getConnectorConfigWithHttpInfo(connectorName)); } @Override public Flux getConnectorPlugins() throws WebClientResponseException { - return withRetryOnConflict(super.getConnectorPlugins()); + return withRetryOnConflictOrRebalance(super.getConnectorPlugins()); } @Override public Mono>> getConnectorPluginsWithHttpInfo() throws WebClientResponseException { - return withRetryOnConflict(super.getConnectorPluginsWithHttpInfo()); + return withRetryOnConflictOrRebalance(super.getConnectorPluginsWithHttpInfo()); } @Override public Mono getConnectorStatus(String connectorName) throws WebClientResponseException { - return withRetryOnConflict(super.getConnectorStatus(connectorName)); + return withRetryOnConflictOrRebalance(super.getConnectorStatus(connectorName)); } @Override public Mono> getConnectorStatusWithHttpInfo(String connectorName) throws WebClientResponseException { - return withRetryOnConflict(super.getConnectorStatusWithHttpInfo(connectorName)); + return withRetryOnConflictOrRebalance(super.getConnectorStatusWithHttpInfo(connectorName)); } @Override public Mono getConnectorTaskStatus(String connectorName, Integer taskId) throws WebClientResponseException { - return withRetryOnConflict(super.getConnectorTaskStatus(connectorName, taskId)); + return withRetryOnConflictOrRebalance(super.getConnectorTaskStatus(connectorName, taskId)); } @Override public Mono> getConnectorTaskStatusWithHttpInfo(String connectorName, Integer taskId) throws WebClientResponseException { - return withRetryOnConflict(super.getConnectorTaskStatusWithHttpInfo(connectorName, taskId)); + return withRetryOnConflictOrRebalance(super.getConnectorTaskStatusWithHttpInfo(connectorName, taskId)); } @Override public Flux getConnectorTasks(String connectorName) throws WebClientResponseException { - return withRetryOnConflict(super.getConnectorTasks(connectorName)); + return withRetryOnConflictOrRebalance(super.getConnectorTasks(connectorName)); } @Override public Mono>> getConnectorTasksWithHttpInfo(String connectorName) throws WebClientResponseException { - return withRetryOnConflict(super.getConnectorTasksWithHttpInfo(connectorName)); + return withRetryOnConflictOrRebalance(super.getConnectorTasksWithHttpInfo(connectorName)); } @Override public Mono> getConnectorTopics(String connectorName) throws WebClientResponseException { - return withRetryOnConflict(super.getConnectorTopics(connectorName)); + return withRetryOnConflictOrRebalance(super.getConnectorTopics(connectorName)); } @Override public Mono>> getConnectorTopicsWithHttpInfo(String connectorName) throws WebClientResponseException { - return withRetryOnConflict(super.getConnectorTopicsWithHttpInfo(connectorName)); + return withRetryOnConflictOrRebalance(super.getConnectorTopicsWithHttpInfo(connectorName)); } @Override public Mono> getConnectors(String search) throws WebClientResponseException { - return withRetryOnConflict(super.getConnectors(search)); + return withRetryOnConflictOrRebalance(super.getConnectors(search)); } @Override public Mono>> getConnectorsWithHttpInfo(String search) throws WebClientResponseException { - return withRetryOnConflict(super.getConnectorsWithHttpInfo(search)); + return withRetryOnConflictOrRebalance(super.getConnectorsWithHttpInfo(search)); } @Override public Mono pauseConnector(String connectorName) throws WebClientResponseException { - return withRetryOnConflict(super.pauseConnector(connectorName)); + return withRetryOnConflictOrRebalance(super.pauseConnector(connectorName)); } @Override public Mono> pauseConnectorWithHttpInfo(String connectorName) throws WebClientResponseException { - return withRetryOnConflict(super.pauseConnectorWithHttpInfo(connectorName)); + return withRetryOnConflictOrRebalance(super.pauseConnectorWithHttpInfo(connectorName)); } @Override public Mono restartConnector(String connectorName, Boolean includeTasks, Boolean onlyFailed) throws WebClientResponseException { - return withRetryOnConflict(super.restartConnector(connectorName, includeTasks, onlyFailed)); + return withRetryOnConflictOrRebalance(super.restartConnector(connectorName, includeTasks, onlyFailed)); } @Override public Mono> restartConnectorWithHttpInfo(String connectorName, Boolean includeTasks, Boolean onlyFailed) throws WebClientResponseException { - return withRetryOnConflict(super.restartConnectorWithHttpInfo(connectorName, includeTasks, onlyFailed)); + return withRetryOnConflictOrRebalance(super.restartConnectorWithHttpInfo(connectorName, includeTasks, onlyFailed)); } @Override public Mono restartConnectorTask(String connectorName, Integer taskId) throws WebClientResponseException { - return withRetryOnConflict(super.restartConnectorTask(connectorName, taskId)); + return withRetryOnConflictOrRebalance(super.restartConnectorTask(connectorName, taskId)); } @Override public Mono> restartConnectorTaskWithHttpInfo(String connectorName, Integer taskId) throws WebClientResponseException { - return withRetryOnConflict(super.restartConnectorTaskWithHttpInfo(connectorName, taskId)); + return withRetryOnConflictOrRebalance(super.restartConnectorTaskWithHttpInfo(connectorName, taskId)); } @Override public Mono resumeConnector(String connectorName) throws WebClientResponseException { - return super.resumeConnector(connectorName); + return withRetryOnRebalance(super.resumeConnector(connectorName)); } @Override public Mono> resumeConnectorWithHttpInfo(String connectorName) throws WebClientResponseException { - return withRetryOnConflict(super.resumeConnectorWithHttpInfo(connectorName)); + return withRetryOnConflictOrRebalance(super.resumeConnectorWithHttpInfo(connectorName)); } @Override public Mono> setConnectorConfigWithHttpInfo(String connectorName, Map requestBody) throws WebClientResponseException { - return withRetryOnConflict(super.setConnectorConfigWithHttpInfo(connectorName, requestBody)); + return withRetryOnConflictOrRebalance(super.setConnectorConfigWithHttpInfo(connectorName, requestBody)); } @Override public Mono validateConnectorPluginConfig(String pluginName, Map requestBody) throws WebClientResponseException { - return withRetryOnConflict(super.validateConnectorPluginConfig(pluginName, requestBody)); + return withRetryOnConflictOrRebalance(super.validateConnectorPluginConfig(pluginName, requestBody)); } @Override public Mono> validateConnectorPluginConfigWithHttpInfo( String pluginName, Map requestBody) throws WebClientResponseException { - return withRetryOnConflict(super.validateConnectorPluginConfigWithHttpInfo(pluginName, requestBody)); + return withRetryOnConflictOrRebalance(super.validateConnectorPluginConfigWithHttpInfo(pluginName, requestBody)); } private static class RetryingApiClient extends ApiClient { diff --git a/api/src/main/java/io/kafbat/ui/config/auth/AbstractAuthSecurityConfig.java b/api/src/main/java/io/kafbat/ui/config/auth/AbstractAuthSecurityConfig.java index dc58a7299..265bac03f 100644 --- a/api/src/main/java/io/kafbat/ui/config/auth/AbstractAuthSecurityConfig.java +++ b/api/src/main/java/io/kafbat/ui/config/auth/AbstractAuthSecurityConfig.java @@ -1,25 +1,53 @@ package io.kafbat.ui.config.auth; +import io.kafbat.ui.util.EmptyRedirectStrategy; +import java.net.URI; +import org.springframework.security.web.server.authentication.RedirectServerAuthenticationSuccessHandler; +import org.springframework.security.web.server.authentication.logout.RedirectServerLogoutSuccessHandler; + abstract class AbstractAuthSecurityConfig { protected AbstractAuthSecurityConfig() { } + protected static final String LOGIN_URL = "/login"; + protected static final String LOGOUT_URL = "/auth?logout"; + protected static final String[] AUTH_WHITELIST = { - "/css/**", - "/js/**", - "/media/**", + /* STATIC */ + "/index.html", + "/assets/**", + "/manifest.json", + "/favicon.svg", + "/favicon/**", + + "/static/**", "/resources/**", + + /* ACTUATOR */ "/actuator/health/**", "/actuator/info", "/actuator/prometheus", - "/auth", + + /* AUTH */ "/login", "/logout", "/oauth2/**", - "/static/**", - "/api/config/authentication" + "/api/config/authentication", + "/api/authorization" }; + protected RedirectServerAuthenticationSuccessHandler emptyRedirectSuccessHandler() { + final var authHandler = new RedirectServerAuthenticationSuccessHandler(); + authHandler.setRedirectStrategy(new EmptyRedirectStrategy()); + return authHandler; + } + + protected RedirectServerLogoutSuccessHandler redirectLogoutSuccessHandler() { + final var logoutSuccessHandler = new RedirectServerLogoutSuccessHandler(); + logoutSuccessHandler.setLogoutSuccessUrl(URI.create(LOGOUT_URL)); + return logoutSuccessHandler; + } + } diff --git a/api/src/main/java/io/kafbat/ui/config/auth/BasicAuthSecurityConfig.java b/api/src/main/java/io/kafbat/ui/config/auth/BasicAuthSecurityConfig.java index 7a25fb3a7..db8ef8153 100644 --- a/api/src/main/java/io/kafbat/ui/config/auth/BasicAuthSecurityConfig.java +++ b/api/src/main/java/io/kafbat/ui/config/auth/BasicAuthSecurityConfig.java @@ -1,6 +1,7 @@ package io.kafbat.ui.config.auth; import io.kafbat.ui.util.EmptyRedirectStrategy; +import io.kafbat.ui.util.StaticFileWebFilter; import java.net.URI; import lombok.extern.slf4j.Slf4j; import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; @@ -8,6 +9,7 @@ import org.springframework.context.annotation.Configuration; import org.springframework.http.HttpMethod; import org.springframework.security.config.annotation.web.reactive.EnableWebFluxSecurity; +import org.springframework.security.config.web.server.SecurityWebFiltersOrder; import org.springframework.security.config.web.server.ServerHttpSecurity; import org.springframework.security.web.server.SecurityWebFilterChain; import org.springframework.security.web.server.authentication.RedirectServerAuthenticationSuccessHandler; @@ -20,32 +22,28 @@ @Slf4j public class BasicAuthSecurityConfig extends AbstractAuthSecurityConfig { - public static final String LOGIN_URL = "/auth"; - public static final String LOGOUT_URL = "/auth?logout"; - @Bean public SecurityWebFilterChain configure(ServerHttpSecurity http) { log.info("Configuring LOGIN_FORM authentication."); - final var authHandler = new RedirectServerAuthenticationSuccessHandler(); - authHandler.setRedirectStrategy(new EmptyRedirectStrategy()); - - final var logoutSuccessHandler = new RedirectServerLogoutSuccessHandler(); - logoutSuccessHandler.setLogoutSuccessUrl(URI.create(LOGOUT_URL)); - - - return http.authorizeExchange(spec -> spec + var builder = http.authorizeExchange(spec -> spec .pathMatchers(AUTH_WHITELIST) .permitAll() .anyExchange() .authenticated() ) - .formLogin(spec -> spec.loginPage(LOGIN_URL).authenticationSuccessHandler(authHandler)) + .formLogin(form -> form + .loginPage(LOGIN_URL) + .authenticationSuccessHandler(emptyRedirectSuccessHandler()) + ) .logout(spec -> spec - .logoutSuccessHandler(logoutSuccessHandler) + .logoutSuccessHandler(redirectLogoutSuccessHandler()) .requiresLogout(ServerWebExchangeMatchers.pathMatchers(HttpMethod.GET, "/logout"))) - .csrf(ServerHttpSecurity.CsrfSpec::disable) - .build(); + .csrf(ServerHttpSecurity.CsrfSpec::disable); + + builder.addFilterAt(new StaticFileWebFilter(), SecurityWebFiltersOrder.LOGIN_PAGE_GENERATING); + + return builder.build(); } } diff --git a/api/src/main/java/io/kafbat/ui/config/auth/LdapSecurityConfig.java b/api/src/main/java/io/kafbat/ui/config/auth/LdapSecurityConfig.java index 1b5a8ca87..4d89a9568 100644 --- a/api/src/main/java/io/kafbat/ui/config/auth/LdapSecurityConfig.java +++ b/api/src/main/java/io/kafbat/ui/config/auth/LdapSecurityConfig.java @@ -1,9 +1,8 @@ package io.kafbat.ui.config.auth; -import static io.kafbat.ui.config.auth.AbstractAuthSecurityConfig.AUTH_WHITELIST; - import io.kafbat.ui.service.rbac.AccessControlService; import io.kafbat.ui.service.rbac.extractor.RbacLdapAuthoritiesExtractor; +import io.kafbat.ui.util.StaticFileWebFilter; import java.util.Collection; import java.util.List; import java.util.Optional; @@ -14,6 +13,7 @@ import org.springframework.context.ApplicationContext; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; +import org.springframework.http.HttpMethod; import org.springframework.ldap.core.DirContextOperations; import org.springframework.ldap.core.support.BaseLdapPathContextSource; import org.springframework.ldap.core.support.LdapContextSource; @@ -21,8 +21,8 @@ import org.springframework.security.authentication.ProviderManager; import org.springframework.security.authentication.ReactiveAuthenticationManager; import org.springframework.security.authentication.ReactiveAuthenticationManagerAdapter; -import org.springframework.security.config.Customizer; import org.springframework.security.config.annotation.web.reactive.EnableWebFluxSecurity; +import org.springframework.security.config.web.server.SecurityWebFiltersOrder; import org.springframework.security.config.web.server.ServerHttpSecurity; import org.springframework.security.core.GrantedAuthority; import org.springframework.security.core.userdetails.UserDetails; @@ -36,6 +36,7 @@ import org.springframework.security.ldap.userdetails.LdapAuthoritiesPopulator; import org.springframework.security.ldap.userdetails.LdapUserDetailsMapper; import org.springframework.security.web.server.SecurityWebFilterChain; +import org.springframework.security.web.server.util.matcher.ServerWebExchangeMatchers; @Configuration @EnableWebFluxSecurity @@ -43,7 +44,7 @@ @EnableConfigurationProperties(LdapProperties.class) @RequiredArgsConstructor @Slf4j -public class LdapSecurityConfig { +public class LdapSecurityConfig extends AbstractAuthSecurityConfig { private final LdapProperties props; @@ -121,16 +122,24 @@ public SecurityWebFilterChain configureLdap(ServerHttpSecurity http) { log.info("Active Directory support for LDAP has been enabled."); } - return http.authorizeExchange(spec -> spec + var builder = http.authorizeExchange(spec -> spec .pathMatchers(AUTH_WHITELIST) .permitAll() .anyExchange() .authenticated() ) - .formLogin(Customizer.withDefaults()) - .logout(Customizer.withDefaults()) - .csrf(ServerHttpSecurity.CsrfSpec::disable) - .build(); + .formLogin(form -> form + .loginPage(LOGIN_URL) + .authenticationSuccessHandler(emptyRedirectSuccessHandler()) + ) + .logout(spec -> spec + .logoutSuccessHandler(redirectLogoutSuccessHandler()) + .requiresLogout(ServerWebExchangeMatchers.pathMatchers(HttpMethod.GET, "/logout"))) + .csrf(ServerHttpSecurity.CsrfSpec::disable); + + builder.addFilterAt(new StaticFileWebFilter(), SecurityWebFiltersOrder.LOGIN_PAGE_GENERATING); + + return builder.build(); } private static class UserDetailsMapper extends LdapUserDetailsMapper { diff --git a/api/src/main/java/io/kafbat/ui/config/auth/OAuthSecurityConfig.java b/api/src/main/java/io/kafbat/ui/config/auth/OAuthSecurityConfig.java index 09c7df794..4794b83ca 100644 --- a/api/src/main/java/io/kafbat/ui/config/auth/OAuthSecurityConfig.java +++ b/api/src/main/java/io/kafbat/ui/config/auth/OAuthSecurityConfig.java @@ -3,6 +3,7 @@ import io.kafbat.ui.config.auth.logout.OAuthLogoutSuccessHandler; import io.kafbat.ui.service.rbac.AccessControlService; import io.kafbat.ui.service.rbac.extractor.ProviderAuthorityExtractor; +import io.kafbat.ui.util.StaticFileWebFilter; import java.util.ArrayList; import java.util.List; import java.util.Map; @@ -19,6 +20,7 @@ import org.springframework.security.config.Customizer; import org.springframework.security.config.annotation.method.configuration.EnableReactiveMethodSecurity; import org.springframework.security.config.annotation.web.reactive.EnableWebFluxSecurity; +import org.springframework.security.config.web.server.SecurityWebFiltersOrder; import org.springframework.security.config.web.server.ServerHttpSecurity; import org.springframework.security.oauth2.client.oidc.userinfo.OidcReactiveOAuth2UserService; import org.springframework.security.oauth2.client.oidc.userinfo.OidcUserRequest; @@ -50,7 +52,7 @@ public class OAuthSecurityConfig extends AbstractAuthSecurityConfig { public SecurityWebFilterChain configure(ServerHttpSecurity http, OAuthLogoutSuccessHandler logoutHandler) { log.info("Configuring OAUTH2 authentication."); - return http.authorizeExchange(spec -> spec + var builder = http.authorizeExchange(spec -> spec .pathMatchers(AUTH_WHITELIST) .permitAll() .anyExchange() @@ -58,8 +60,12 @@ public SecurityWebFilterChain configure(ServerHttpSecurity http, OAuthLogoutSucc ) .oauth2Login(Customizer.withDefaults()) .logout(spec -> spec.logoutSuccessHandler(logoutHandler)) - .csrf(ServerHttpSecurity.CsrfSpec::disable) - .build(); + .csrf(ServerHttpSecurity.CsrfSpec::disable); + + + builder.addFilterAt(new StaticFileWebFilter(), SecurityWebFiltersOrder.LOGIN_PAGE_GENERATING); + + return builder.build(); } @Bean diff --git a/api/src/main/java/io/kafbat/ui/controller/AuthenticationController.java b/api/src/main/java/io/kafbat/ui/controller/AuthenticationController.java index b50c64546..c94c344c9 100644 --- a/api/src/main/java/io/kafbat/ui/controller/AuthenticationController.java +++ b/api/src/main/java/io/kafbat/ui/controller/AuthenticationController.java @@ -1,13 +1,10 @@ package io.kafbat.ui.controller; -import java.nio.charset.Charset; import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; -import org.springframework.security.web.server.csrf.CsrfToken; -import org.springframework.util.MultiValueMap; +import org.springframework.core.io.ClassPathResource; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.RestController; -import org.springframework.web.server.ServerWebExchange; import reactor.core.publisher.Mono; @RestController @@ -15,85 +12,11 @@ @Slf4j public class AuthenticationController { - @GetMapping(value = "/auth", produces = {"text/html"}) - public Mono getAuth(ServerWebExchange exchange) { - Mono token = exchange.getAttributeOrDefault(CsrfToken.class.getName(), Mono.empty()); - return token - .map(AuthenticationController::csrfToken) - .defaultIfEmpty("") - .map(csrfTokenHtmlInput -> createPage(exchange, csrfTokenHtmlInput)); - } - - private byte[] createPage(ServerWebExchange exchange, String csrfTokenHtmlInput) { - MultiValueMap queryParams = exchange.getRequest() - .getQueryParams(); - String contextPath = exchange.getRequest().getPath().contextPath().value(); - String page = - "\n" + "\n" + " \n" - + " \n" - + " \n" - + " \n" - + " \n" - + " Please sign in\n" - + " \n" - + " \n" - + " \n" - + " \n" - + "
\n" - + formLogin(queryParams, contextPath, csrfTokenHtmlInput) - + "
\n" - + " \n" - + ""; - - return page.getBytes(Charset.defaultCharset()); - } - - private String formLogin( - MultiValueMap queryParams, - String contextPath, String csrfTokenHtmlInput) { + private static final String INDEX_HTML = "/static/index.html"; - boolean isError = queryParams.containsKey("error"); - boolean isLogoutSuccess = queryParams.containsKey("logout"); - return - "
\n" - + " \n" - + createError(isError) - + createLogoutSuccess(isLogoutSuccess) - + "

\n" - + " \n" - + " \n" - + "

\n" + "

\n" - + " \n" - + " \n" - + "

\n" + csrfTokenHtmlInput - + " \n" - + "
\n"; + @GetMapping(value = "/login", produces = {"text/html"}) + public Mono getLoginPage() { + return Mono.just(new ClassPathResource(INDEX_HTML)); } - private static String csrfToken(CsrfToken token) { - return " \n"; - } - - private static String createError(boolean isError) { - return isError - ? "
Invalid credentials
" - : ""; - } - - private static String createLogoutSuccess(boolean isLogoutSuccess) { - return isLogoutSuccess - ? "
You have been signed out
" - : ""; - } } diff --git a/api/src/main/java/io/kafbat/ui/serdes/builtin/ProtobufFileSerde.java b/api/src/main/java/io/kafbat/ui/serdes/builtin/ProtobufFileSerde.java index 51c921603..723474cae 100644 --- a/api/src/main/java/io/kafbat/ui/serdes/builtin/ProtobufFileSerde.java +++ b/api/src/main/java/io/kafbat/ui/serdes/builtin/ProtobufFileSerde.java @@ -15,6 +15,7 @@ import com.google.protobuf.StructProto; import com.google.protobuf.TimestampProto; import com.google.protobuf.TypeProto; +import com.google.protobuf.TypeRegistry; import com.google.protobuf.WrappersProto; import com.google.protobuf.util.JsonFormat; import com.google.type.ColorProto; @@ -147,12 +148,18 @@ public boolean canSerialize(String topic, Serde.Target type) { @Override public Serde.Serializer serializer(String topic, Serde.Target type) { var descriptor = descriptorFor(topic, type).orElseThrow(); + TypeRegistry typeRegistry = TypeRegistry.newBuilder() + .add(descriptorPaths.keySet()) + .build(); + return new Serde.Serializer() { @SneakyThrows @Override public byte[] serialize(String input) { DynamicMessage.Builder builder = DynamicMessage.newBuilder(descriptor); - JsonFormat.parser().merge(input, builder); + JsonFormat.parser() + .usingTypeRegistry(typeRegistry) + .merge(input, builder); return builder.build().toByteArray(); } }; diff --git a/api/src/main/java/io/kafbat/ui/util/StaticFileWebFilter.java b/api/src/main/java/io/kafbat/ui/util/StaticFileWebFilter.java new file mode 100644 index 000000000..1b74bd374 --- /dev/null +++ b/api/src/main/java/io/kafbat/ui/util/StaticFileWebFilter.java @@ -0,0 +1,61 @@ +package io.kafbat.ui.util; + +import java.io.IOException; +import org.jetbrains.annotations.NotNull; +import org.springframework.core.io.ClassPathResource; +import org.springframework.core.io.buffer.DataBufferFactory; +import org.springframework.http.HttpMethod; +import org.springframework.http.HttpStatus; +import org.springframework.http.MediaType; +import org.springframework.http.server.reactive.ServerHttpResponse; +import org.springframework.security.web.server.util.matcher.ServerWebExchangeMatcher; +import org.springframework.security.web.server.util.matcher.ServerWebExchangeMatchers; +import org.springframework.web.server.ServerWebExchange; +import org.springframework.web.server.WebFilter; +import org.springframework.web.server.WebFilterChain; +import reactor.core.publisher.Mono; + +public class StaticFileWebFilter implements WebFilter { + + private static final String INDEX_HTML = "/static/index.html"; + + private final ServerWebExchangeMatcher matcher; + private final String contents; + + public StaticFileWebFilter() { + this("/login", new ClassPathResource(INDEX_HTML)); + } + + public StaticFileWebFilter(String path, ClassPathResource resource) { + this.matcher = ServerWebExchangeMatchers.pathMatchers(HttpMethod.GET, path); + + try { + this.contents = ResourceUtil.readAsString(resource); + } catch (IOException e) { + throw new RuntimeException(e); + } + } + + @Override + public @NotNull Mono filter(@NotNull ServerWebExchange exchange, WebFilterChain chain) { + return this.matcher.matches(exchange) + .filter(ServerWebExchangeMatcher.MatchResult::isMatch) + .switchIfEmpty(chain.filter(exchange).then(Mono.empty())) + .flatMap((matchResult) -> this.render(exchange)); + } + + private Mono render(ServerWebExchange exchange) { + String contextPath = exchange.getRequest().getPath().contextPath().value(); + + String contentBody = contents + .replace("\"assets/", "\"" + contextPath + "/assets/") + .replace("PUBLIC-PATH-VARIABLE", contextPath); + + ServerHttpResponse result = exchange.getResponse(); + result.setStatusCode(HttpStatus.OK); + result.getHeaders().setContentType(MediaType.TEXT_HTML); + DataBufferFactory bufferFactory = exchange.getResponse().bufferFactory(); + return result.writeWith(Mono.just(bufferFactory.wrap(contentBody.getBytes()))); + } + +} diff --git a/api/src/test/java/io/kafbat/ui/AbstractIntegrationTest.java b/api/src/test/java/io/kafbat/ui/AbstractIntegrationTest.java index 554387a1a..7224649b1 100644 --- a/api/src/test/java/io/kafbat/ui/AbstractIntegrationTest.java +++ b/api/src/test/java/io/kafbat/ui/AbstractIntegrationTest.java @@ -5,6 +5,7 @@ import io.kafbat.ui.container.KafkaConnectContainer; import io.kafbat.ui.container.KsqlDbContainer; import io.kafbat.ui.container.SchemaRegistryContainer; +import java.io.FileNotFoundException; import java.nio.file.Path; import java.util.List; import java.util.Properties; @@ -22,6 +23,7 @@ import org.springframework.test.context.ActiveProfiles; import org.springframework.test.context.ContextConfiguration; import org.springframework.test.util.TestSocketUtils; +import org.springframework.util.ResourceUtils; import org.testcontainers.containers.KafkaContainer; import org.testcontainers.containers.Network; import org.testcontainers.utility.DockerImageName; @@ -38,7 +40,7 @@ public abstract class AbstractIntegrationTest { private static final boolean IS_ARM = System.getProperty("os.arch").contains("arm") || System.getProperty("os.arch").contains("aarch64"); - private static final String CONFLUENT_PLATFORM_VERSION = IS_ARM ? "7.2.1.arm64" : "7.2.1"; + private static final String CONFLUENT_PLATFORM_VERSION = IS_ARM ? "7.8.0.arm64" : "7.8.0"; public static final KafkaContainer kafka = new KafkaContainer( DockerImageName.parse("confluentinc/cp-kafka").withTag(CONFLUENT_PLATFORM_VERSION)) @@ -75,6 +77,18 @@ public static class Initializer public void initialize(@NotNull ConfigurableApplicationContext context) { System.setProperty("kafka.clusters.0.name", LOCAL); System.setProperty("kafka.clusters.0.bootstrapServers", kafka.getBootstrapServers()); + + // Add ProtobufFileSerde configuration + System.setProperty("kafka.clusters.0.serde.0.name", "ProtobufFile"); + System.setProperty("kafka.clusters.0.serde.0.topicValuesPattern", "masking-test-.*"); + try { + System.setProperty("kafka.clusters.0.serde.0.properties.protobufFilesDir", + ResourceUtils.getFile("classpath:protobuf-serde").getAbsolutePath()); + } catch (FileNotFoundException e) { + throw new RuntimeException(e); + } + System.setProperty("kafka.clusters.0.serde.0.properties.protobufMessageName", "test.MessageWithAny"); + // List unavailable hosts to verify failover System.setProperty("kafka.clusters.0.schemaRegistry", String.format("http://localhost:%1$s,http://localhost:%1$s,%2$s", diff --git a/api/src/test/java/io/kafbat/ui/serdes/builtin/ProtobufFileSerdeTest.java b/api/src/test/java/io/kafbat/ui/serdes/builtin/ProtobufFileSerdeTest.java index 069f9ed45..becccafa6 100644 --- a/api/src/test/java/io/kafbat/ui/serdes/builtin/ProtobufFileSerdeTest.java +++ b/api/src/test/java/io/kafbat/ui/serdes/builtin/ProtobufFileSerdeTest.java @@ -80,14 +80,15 @@ void setUp() throws Exception { void loadsAllProtoFiledFromTargetDirectory() throws Exception { var protoDir = ResourceUtils.getFile("classpath:protobuf-serde/").getPath(); List files = new ProtobufFileSerde.ProtoSchemaLoader(protoDir).load(); - assertThat(files).hasSize(4); + assertThat(files).hasSize(5); assertThat(files) .map(f -> f.getLocation().getPath()) .containsExactlyInAnyOrder( "language/language.proto", "sensor.proto", "address-book.proto", - "lang-description.proto" + "lang-description.proto", + "messagewithany.proto" ); } diff --git a/api/src/test/java/io/kafbat/ui/service/MessagesServiceTest.java b/api/src/test/java/io/kafbat/ui/service/MessagesServiceTest.java index 849daefd6..1fecae247 100644 --- a/api/src/test/java/io/kafbat/ui/service/MessagesServiceTest.java +++ b/api/src/test/java/io/kafbat/ui/service/MessagesServiceTest.java @@ -13,6 +13,7 @@ import io.kafbat.ui.model.TopicMessageDTO; import io.kafbat.ui.model.TopicMessageEventDTO; import io.kafbat.ui.producer.KafkaTestProducer; +import io.kafbat.ui.serdes.builtin.ProtobufFileSerde; import io.kafbat.ui.serdes.builtin.StringSerde; import java.util.HashSet; import java.util.List; @@ -214,4 +215,33 @@ void execSmartFilterTestReturnsErrorOnFilterCompilationError() { assertThat(result.getError()).containsIgnoringCase("Compilation error"); } + @Test + void sendMessageWithProtobufAnyType() { + String jsonContent = """ + { + "name": "testName", + "payload": { + "@type": "type.googleapis.com/test.PayloadMessage", + "id": "123" + } + } + """; + + CreateTopicMessageDTO testMessage = new CreateTopicMessageDTO() + .key(null) + .partition(0) + .keySerde(StringSerde.name()) + .content(jsonContent) + .valueSerde(ProtobufFileSerde.name()); + + String testTopic = MASKED_TOPICS_PREFIX + UUID.randomUUID(); + createTopicWithCleanup(new NewTopic(testTopic, 5, (short) 1)); + + StepVerifier.create(messagesService.sendMessage(cluster, testTopic, testMessage)) + .expectNextMatches(metadata -> metadata.topic().equals(testTopic) + && metadata.partition() == 0 + && metadata.offset() >= 0) + .verifyComplete(); + } + } diff --git a/api/src/test/resources/protobuf-serde/messagewithany.proto b/api/src/test/resources/protobuf-serde/messagewithany.proto new file mode 100644 index 000000000..5a4b0dd64 --- /dev/null +++ b/api/src/test/resources/protobuf-serde/messagewithany.proto @@ -0,0 +1,13 @@ +syntax = "proto3"; +package test; + +import "google/protobuf/any.proto"; + +message MessageWithAny { + string name = 1; + google.protobuf.Any payload = 2; +} + +message PayloadMessage { + string id = 1; +} diff --git a/contract/src/main/resources/swagger/kafbat-ui-api.yaml b/contract/src/main/resources/swagger/kafbat-ui-api.yaml index 2e0c8df14..dff80b4ce 100644 --- a/contract/src/main/resources/swagger/kafbat-ui-api.yaml +++ b/contract/src/main/resources/swagger/kafbat-ui-api.yaml @@ -2254,12 +2254,9 @@ paths: schema: $ref: '#/components/schemas/AppAuthenticationSettings' - /auth: + /login: post: - tags: - - Unmapped summary: Authenticate - operationId: authenticate requestBody: required: true content: diff --git a/documentation/compose/e2e-tests.yaml b/documentation/compose/e2e-tests.yaml index da986cc39..e18eb7a16 100644 --- a/documentation/compose/e2e-tests.yaml +++ b/documentation/compose/e2e-tests.yaml @@ -29,7 +29,7 @@ services: KAFKA_CLUSTERS_0_KSQLDBSERVER: http://ksqldb:8088 kafka0: - image: confluentinc/cp-kafka:7.6.0 + image: confluentinc/cp-kafka:7.8.0 user: "0:0" hostname: kafka0 container_name: kafka0 @@ -62,7 +62,7 @@ services: CLUSTER_ID: 'MkU3OEVBNTcwNTJENDM2Qk' schemaregistry0: - image: confluentinc/cp-schema-registry:7.6.0 + image: confluentinc/cp-schema-registry:7.8.0 ports: - 8085:8085 depends_on: @@ -87,7 +87,7 @@ services: build: context: ./kafka-connect args: - image: confluentinc/cp-kafka-connect:7.6.0 + image: confluentinc/cp-kafka-connect:7.8.0 ports: - 8083:8083 depends_on: @@ -121,7 +121,7 @@ services: # AWS_SECRET_ACCESS_KEY: "" kafka-init-topics: - image: confluentinc/cp-kafka:7.6.0 + image: confluentinc/cp-kafka:7.8.0 volumes: - ./data/message.json:/data/message.json depends_on: @@ -161,7 +161,7 @@ services: command: sh -c '/connectors/start.sh' ksqldb: - image: confluentinc/cp-ksqldb-server:7.6.0 + image: confluentinc/cp-ksqldb-server:7.8.0 healthcheck: test: [ "CMD", "timeout", "1", "curl", "--silent", "--fail", "http://localhost:8088/info" ] interval: 30s diff --git a/e2e-tests/pom.xml b/e2e-tests/pom.xml index 8131dd11d..33db9404d 100644 --- a/e2e-tests/pom.xml +++ b/e2e-tests/pom.xml @@ -12,7 +12,6 @@ e2e-tests - 3.8.0 ${project.version} 21 3.5.1 @@ -25,7 +24,7 @@ org.apache.kafka kafka_2.13 - ${kafka.version} + ${confluent.version}-ccs io.kafbat.ui diff --git a/e2e-tests/src/main/java/io/kafbat/ui/screens/panels/NaviSideBar.java b/e2e-tests/src/main/java/io/kafbat/ui/screens/panels/NaviSideBar.java index 6972f379d..b5dc2be8d 100644 --- a/e2e-tests/src/main/java/io/kafbat/ui/screens/panels/NaviSideBar.java +++ b/e2e-tests/src/main/java/io/kafbat/ui/screens/panels/NaviSideBar.java @@ -13,6 +13,7 @@ import java.util.List; import java.util.stream.Collectors; import java.util.stream.Stream; +import org.openqa.selenium.By; public class NaviSideBar extends BasePage { @@ -45,7 +46,7 @@ public String getPagePath(MenuItem menuItem) { @Step public NaviSideBar openSideMenu(String clusterName, MenuItem menuItem) { WebUtil.clickByActions(expandCluster(clusterName).parent() - .$x(String.format(sideMenuOptionElementLocator, menuItem.getNaviTitle()))); + .find(By.linkText(menuItem.getNaviTitle()))); return this; } diff --git a/e2e-tests/src/main/java/io/kafbat/ui/screens/topics/TopicSettingsTab.java b/e2e-tests/src/main/java/io/kafbat/ui/screens/topics/TopicSettingsTab.java index ef32fe352..75e3fe8e7 100644 --- a/e2e-tests/src/main/java/io/kafbat/ui/screens/topics/TopicSettingsTab.java +++ b/e2e-tests/src/main/java/io/kafbat/ui/screens/topics/TopicSettingsTab.java @@ -9,10 +9,13 @@ import io.qameta.allure.Step; import java.util.ArrayList; import java.util.List; +import java.util.NoSuchElementException; public class TopicSettingsTab extends BasePage { protected SelenideElement defaultValueColumnHeaderLocator = $x("//div[text() = 'Default Value']"); + protected SelenideElement nextButton = $x("//button[contains(text(), 'Next')]"); + protected SelenideElement previousButton = $x("//button[contains(text(), 'Previous')]"); @Step public TopicSettingsTab waitUntilScreenReady() { @@ -36,7 +39,25 @@ private TopicSettingsTab.SettingsGridItem getItemByKey(String key) { @Step public String getValueByKey(String key) { - return getItemByKey(key).getValue(); + while (true) { + try { + String value = getItemByKey(key).getValue(); + resetPageNavigation(); + return value; + } catch (NoSuchElementException e) { + if (nextButton.isEnabled()) { + nextButton.click(); + } else { + throw e; + } + } + } + } + + private void resetPageNavigation() { + while (previousButton.isEnabled()) { + previousButton.click(); + } } public static class SettingsGridItem extends BasePage { diff --git a/frontend/package.json b/frontend/package.json index 4331b281b..249c91a8f 100644 --- a/frontend/package.json +++ b/frontend/package.json @@ -16,7 +16,7 @@ "ajv": "8.8.2", "ajv-formats": "2.1.1", "json-schema-faker": "0.5.6", - "jsonpath-plus": "8.1.0", + "jsonpath-plus": "10.0.7", "lossless-json": "2.0.11", "pretty-ms": "7.0.1", "react": "18.2.0", @@ -96,7 +96,7 @@ "ts-node": "10.9.2", "ts-prune": "0.10.3", "typescript": "5.3.3", - "vite": "5.2.10", + "vite": "5.2.14", "vite-plugin-checker": "0.6.4", "vite-plugin-ejs": "1.7.0", "vite-tsconfig-paths": "4.3.2", diff --git a/frontend/pnpm-lock.yaml b/frontend/pnpm-lock.yaml index 4474bab46..29518a5cf 100644 --- a/frontend/pnpm-lock.yaml +++ b/frontend/pnpm-lock.yaml @@ -57,8 +57,8 @@ importers: specifier: 0.5.6 version: 0.5.6 jsonpath-plus: - specifier: 8.1.0 - version: 8.1.0 + specifier: 10.0.7 + version: 10.0.7 lossless-json: specifier: 2.0.11 version: 2.0.11 @@ -170,7 +170,7 @@ importers: version: 6.21.0(eslint@8.57.0)(typescript@5.3.3) '@vitejs/plugin-react-swc': specifier: 3.6.0 - version: 3.6.0(vite@5.2.10(@types/node@20.11.17)(sass@1.66.1)) + version: 3.6.0(vite@5.2.14(@types/node@20.11.17)(sass@1.66.1)) dotenv: specifier: 16.4.5 version: 16.4.5 @@ -179,10 +179,10 @@ importers: version: 8.57.0 eslint-config-airbnb: specifier: 19.0.4 - version: 19.0.4(eslint-plugin-import@2.29.1(@typescript-eslint/parser@6.21.0(eslint@8.57.0)(typescript@5.3.3))(eslint-import-resolver-typescript@3.6.1)(eslint@8.57.0))(eslint-plugin-jsx-a11y@6.8.0(eslint@8.57.0))(eslint-plugin-react-hooks@4.6.0(eslint@8.57.0))(eslint-plugin-react@7.34.1(eslint@8.57.0))(eslint@8.57.0) + version: 19.0.4(eslint-plugin-import@2.29.1)(eslint-plugin-jsx-a11y@6.8.0(eslint@8.57.0))(eslint-plugin-react-hooks@4.6.0(eslint@8.57.0))(eslint-plugin-react@7.34.1(eslint@8.57.0))(eslint@8.57.0) eslint-config-airbnb-typescript: specifier: 18.0.0 - version: 18.0.0(@typescript-eslint/eslint-plugin@6.21.0(@typescript-eslint/parser@6.21.0(eslint@8.57.0)(typescript@5.3.3))(eslint@8.57.0)(typescript@5.3.3))(@typescript-eslint/parser@6.21.0(eslint@8.57.0)(typescript@5.3.3))(eslint-plugin-import@2.29.1(@typescript-eslint/parser@6.21.0(eslint@8.57.0)(typescript@5.3.3))(eslint-import-resolver-typescript@3.6.1)(eslint@8.57.0))(eslint@8.57.0) + version: 18.0.0(@typescript-eslint/eslint-plugin@6.21.0(@typescript-eslint/parser@6.21.0(eslint@8.57.0)(typescript@5.3.3))(eslint@8.57.0)(typescript@5.3.3))(@typescript-eslint/parser@6.21.0(eslint@8.57.0)(typescript@5.3.3))(eslint-plugin-import@2.29.1)(eslint@8.57.0) eslint-config-prettier: specifier: 9.1.0 version: 9.1.0(eslint@8.57.0) @@ -244,17 +244,17 @@ importers: specifier: 5.3.3 version: 5.3.3 vite: - specifier: 5.2.10 - version: 5.2.10(@types/node@20.11.17)(sass@1.66.1) + specifier: 5.2.14 + version: 5.2.14(@types/node@20.11.17)(sass@1.66.1) vite-plugin-checker: specifier: 0.6.4 - version: 0.6.4(eslint@8.57.0)(optionator@0.9.3)(typescript@5.3.3)(vite@5.2.10(@types/node@20.11.17)(sass@1.66.1)) + version: 0.6.4(eslint@8.57.0)(optionator@0.9.3)(typescript@5.3.3)(vite@5.2.14(@types/node@20.11.17)(sass@1.66.1)) vite-plugin-ejs: specifier: 1.7.0 - version: 1.7.0(vite@5.2.10(@types/node@20.11.17)(sass@1.66.1)) + version: 1.7.0(vite@5.2.14(@types/node@20.11.17)(sass@1.66.1)) vite-tsconfig-paths: specifier: 4.3.2 - version: 4.3.2(typescript@5.3.3)(vite@5.2.10(@types/node@20.11.17)(sass@1.66.1)) + version: 4.3.2(typescript@5.3.3)(vite@5.2.14(@types/node@20.11.17)(sass@1.66.1)) whatwg-fetch: specifier: 3.6.20 version: 3.6.20 @@ -667,6 +667,7 @@ packages: '@humanwhocodes/config-array@0.11.14': resolution: {integrity: sha512-3T8LkOmg45BV5FICb15QQMsyUSWrQ8AygVfC7ZG32zOalnqrilm018ZVCw0eapXux8FtA33q8PSRSstjee3jSg==} engines: {node: '>=10.10.0'} + deprecated: Use @eslint/config-array instead '@humanwhocodes/module-importer@1.0.1': resolution: {integrity: sha512-bxveV4V8v5Yb4ncFTT3rPSgZBOpCkjfK0y4oVVVJwIuDVBRMDXrPyXRL988i5ap9m9bnyEEjWfm5WkBmtffLfA==} @@ -674,6 +675,7 @@ packages: '@humanwhocodes/object-schema@2.0.3': resolution: {integrity: sha512-93zYdMES/c1D69yZiKDBj0V24vqNzB/koF26KPaagAfd3P/4gUlh3Dys5ogAK+Exi9QyzlD8x/08Zt7wIKcDcA==} + deprecated: Use @eslint/object-schema instead '@isaacs/cliui@8.0.2': resolution: {integrity: sha512-O8jcjabXaleOG9DQ0+ARXWZBTfnP4WNAqzuiJK7ll44AmxGKv/J2M4TPjxjY3znBCfvBXFzucm1twdyFybFqEA==} @@ -790,6 +792,18 @@ packages: '@jridgewell/trace-mapping@0.3.9': resolution: {integrity: sha512-3Belt6tdc8bPgAtbcmdtNJlirVoTmEb5e2gC94PnkwEW9jI6CAHUeoG85tjWP5WquqfavoMtMwiG4P926ZKKuQ==} + '@jsep-plugin/assignment@1.3.0': + resolution: {integrity: sha512-VVgV+CXrhbMI3aSusQyclHkenWSAm95WaiKrMxRFam3JSUiIaQjoMIw2sEs/OX4XifnqeQUN4DYbJjlA8EfktQ==} + engines: {node: '>= 10.16.0'} + peerDependencies: + jsep: ^0.4.0||^1.0.0 + + '@jsep-plugin/regex@1.0.4': + resolution: {integrity: sha512-q7qL4Mgjs1vByCaTnDFcBnV9HS7GVPJX5vyVoCgZHNSC9rjwIlmbXG5sUuorR5ndfHAIlJ8pVStxvjXHbNvtUg==} + engines: {node: '>= 10.16.0'} + peerDependencies: + jsep: ^0.4.0||^1.0.0 + '@lukeed/csprng@1.1.0': resolution: {integrity: sha512-Z7C/xXCiGWsg0KuKsHTKJxbWhpI3Vs5GwLfOean7MGyVFGqdRgBbAjOCh6u4bbjPc/8MJ2pZmK/0DLdCbivLDA==} engines: {node: '>=8'} @@ -868,83 +882,98 @@ packages: resolution: {integrity: sha512-Quz1KOffeEf/zwkCBM3kBtH4ZoZ+pT3xIXBG4PPW/XFtDP7EGhtTiC2+gpL9GnR7+Qdet5Oa6cYSvwKYg6kN9Q==} engines: {node: '>=14.0.0'} - '@rollup/rollup-android-arm-eabi@4.16.1': - resolution: {integrity: sha512-92/y0TqNLRYOTXpm6Z7mnpvKAG9P7qmK7yJeRJSdzElNCUnsgbpAsGqerUboYRIQKzgfq4pWu9xVkgpWLfmNsw==} + '@rollup/rollup-android-arm-eabi@4.29.1': + resolution: {integrity: sha512-ssKhA8RNltTZLpG6/QNkCSge+7mBQGUqJRisZ2MDQcEGaK93QESEgWK2iOpIDZ7k9zPVkG5AS3ksvD5ZWxmItw==} cpu: [arm] os: [android] - '@rollup/rollup-android-arm64@4.16.1': - resolution: {integrity: sha512-ttWB6ZCfRLuDIUiE0yiu5gcqOsYjA5F7kEV1ggHMj20FwLZ8A1FMeahZJFl/pnOmcnD2QL0z4AcDuo27utGU8A==} + '@rollup/rollup-android-arm64@4.29.1': + resolution: {integrity: sha512-CaRfrV0cd+NIIcVVN/jx+hVLN+VRqnuzLRmfmlzpOzB87ajixsN/+9L5xNmkaUUvEbI5BmIKS+XTwXsHEb65Ew==} cpu: [arm64] os: [android] - '@rollup/rollup-darwin-arm64@4.16.1': - resolution: {integrity: sha512-QLDvPLetbqjHojTGFw9+nuSP3YY/iz2k1cep6crYlr97sS+ZJ0W43b8Z0zC00+lnFZj6JSNxiA4DjboNQMuh1A==} + '@rollup/rollup-darwin-arm64@4.29.1': + resolution: {integrity: sha512-2ORr7T31Y0Mnk6qNuwtyNmy14MunTAMx06VAPI6/Ju52W10zk1i7i5U3vlDRWjhOI5quBcrvhkCHyF76bI7kEw==} cpu: [arm64] os: [darwin] - '@rollup/rollup-darwin-x64@4.16.1': - resolution: {integrity: sha512-TAUK/D8khRrRIa1KwRzo8JNKk3tcqaeXWdtsiLgA8zmACWwlWLjPCJ4DULGHQrMkeBjp1Cd3Yuwx04lZgFx5Vg==} + '@rollup/rollup-darwin-x64@4.29.1': + resolution: {integrity: sha512-j/Ej1oanzPjmN0tirRd5K2/nncAhS9W6ICzgxV+9Y5ZsP0hiGhHJXZ2JQ53iSSjj8m6cRY6oB1GMzNn2EUt6Ng==} cpu: [x64] os: [darwin] - '@rollup/rollup-linux-arm-gnueabihf@4.16.1': - resolution: {integrity: sha512-KO+WGZjrh6zyFTD1alIFkfdtxf8B4BC+hqd3kBZHscPLvE5FR/6QKsyuCT0JlERxxYBSUKNUQ/UHyX5uwO1x2A==} + '@rollup/rollup-freebsd-arm64@4.29.1': + resolution: {integrity: sha512-91C//G6Dm/cv724tpt7nTyP+JdN12iqeXGFM1SqnljCmi5yTXriH7B1r8AD9dAZByHpKAumqP1Qy2vVNIdLZqw==} + cpu: [arm64] + os: [freebsd] + + '@rollup/rollup-freebsd-x64@4.29.1': + resolution: {integrity: sha512-hEioiEQ9Dec2nIRoeHUP6hr1PSkXzQaCUyqBDQ9I9ik4gCXQZjJMIVzoNLBRGet+hIUb3CISMh9KXuCcWVW/8w==} + cpu: [x64] + os: [freebsd] + + '@rollup/rollup-linux-arm-gnueabihf@4.29.1': + resolution: {integrity: sha512-Py5vFd5HWYN9zxBv3WMrLAXY3yYJ6Q/aVERoeUFwiDGiMOWsMs7FokXihSOaT/PMWUty/Pj60XDQndK3eAfE6A==} cpu: [arm] os: [linux] - '@rollup/rollup-linux-arm-musleabihf@4.16.1': - resolution: {integrity: sha512-NqxbllzIB1WoAo4ThUXVtd21iiM5IHMTTXmXySKBLVcZvkU0HIZmatlP7hLzb5yQubcmdIeWmncd2NdsjocEiw==} + '@rollup/rollup-linux-arm-musleabihf@4.29.1': + resolution: {integrity: sha512-RiWpGgbayf7LUcuSNIbahr0ys2YnEERD4gYdISA06wa0i8RALrnzflh9Wxii7zQJEB2/Eh74dX4y/sHKLWp5uQ==} cpu: [arm] os: [linux] - '@rollup/rollup-linux-arm64-gnu@4.16.1': - resolution: {integrity: sha512-snma5NvV8y7IECQ5rq0sr0f3UUu+92NVmG/913JXJMcXo84h9ak9TA5UI9Cl2XRM9j3m37QwDBtEYnJzRkSmxA==} + '@rollup/rollup-linux-arm64-gnu@4.29.1': + resolution: {integrity: sha512-Z80O+taYxTQITWMjm/YqNoe9d10OX6kDh8X5/rFCMuPqsKsSyDilvfg+vd3iXIqtfmp+cnfL1UrYirkaF8SBZA==} cpu: [arm64] os: [linux] - '@rollup/rollup-linux-arm64-musl@4.16.1': - resolution: {integrity: sha512-KOvqGprlD84ueivhCi2flvcUwDRD20mAsE3vxQNVEI2Di9tnPGAfEu6UcrSPZbM+jG2w1oSr43hrPo0RNg6GGg==} + '@rollup/rollup-linux-arm64-musl@4.29.1': + resolution: {integrity: sha512-fOHRtF9gahwJk3QVp01a/GqS4hBEZCV1oKglVVq13kcK3NeVlS4BwIFzOHDbmKzt3i0OuHG4zfRP0YoG5OF/rA==} cpu: [arm64] os: [linux] - '@rollup/rollup-linux-powerpc64le-gnu@4.16.1': - resolution: {integrity: sha512-/gsNwtiGLqYwN4vP+EIdUC6Q6LTlpupWqokqIndvZcjn9ig/5P01WyaYCU2wvfL/2Z82jp5kX8c1mDBOvCP3zg==} + '@rollup/rollup-linux-loongarch64-gnu@4.29.1': + resolution: {integrity: sha512-5a7q3tnlbcg0OodyxcAdrrCxFi0DgXJSoOuidFUzHZ2GixZXQs6Tc3CHmlvqKAmOs5eRde+JJxeIf9DonkmYkw==} + cpu: [loong64] + os: [linux] + + '@rollup/rollup-linux-powerpc64le-gnu@4.29.1': + resolution: {integrity: sha512-9b4Mg5Yfz6mRnlSPIdROcfw1BU22FQxmfjlp/CShWwO3LilKQuMISMTtAu/bxmmrE6A902W2cZJuzx8+gJ8e9w==} cpu: [ppc64] os: [linux] - '@rollup/rollup-linux-riscv64-gnu@4.16.1': - resolution: {integrity: sha512-uU8zuGkQfGqfD9w6VRJZI4IuG4JIfNxxJgEmLMAmPVHREKGsxFVfgHy5c6CexQF2vOfgjB33OsET3Vdn2lln9A==} + '@rollup/rollup-linux-riscv64-gnu@4.29.1': + resolution: {integrity: sha512-G5pn0NChlbRM8OJWpJFMX4/i8OEU538uiSv0P6roZcbpe/WfhEO+AT8SHVKfp8qhDQzaz7Q+1/ixMy7hBRidnQ==} cpu: [riscv64] os: [linux] - '@rollup/rollup-linux-s390x-gnu@4.16.1': - resolution: {integrity: sha512-lsjLtDgtcGFEuBP6yrXwkRN5/wKlvUZtfbKZZu0yaoNpiBL4epgnO21osAALIspVRnl4qZgyLFd8xjCYYWgwfw==} + '@rollup/rollup-linux-s390x-gnu@4.29.1': + resolution: {integrity: sha512-WM9lIkNdkhVwiArmLxFXpWndFGuOka4oJOZh8EP3Vb8q5lzdSCBuhjavJsw68Q9AKDGeOOIHYzYm4ZFvmWez5g==} cpu: [s390x] os: [linux] - '@rollup/rollup-linux-x64-gnu@4.16.1': - resolution: {integrity: sha512-N2ZizKhUryqqrMfdCnjhJhZRgv61C6gK+hwVtCIKC8ts8J+go+vqENnGexwg21nHIOvLN5mBM8a7DI2vlyIOPg==} + '@rollup/rollup-linux-x64-gnu@4.29.1': + resolution: {integrity: sha512-87xYCwb0cPGZFoGiErT1eDcssByaLX4fc0z2nRM6eMtV9njAfEE6OW3UniAoDhX4Iq5xQVpE6qO9aJbCFumKYQ==} cpu: [x64] os: [linux] - '@rollup/rollup-linux-x64-musl@4.16.1': - resolution: {integrity: sha512-5ICeMxqg66FrOA2AbnBQ2TJVxfvZsKLxmof0ibvPLaYtbsJqnTUtJOofgWb46Gjd4uZcA4rdsp4JCxegzQPqCg==} + '@rollup/rollup-linux-x64-musl@4.29.1': + resolution: {integrity: sha512-xufkSNppNOdVRCEC4WKvlR1FBDyqCSCpQeMMgv9ZyXqqtKBfkw1yfGMTUTs9Qsl6WQbJnsGboWCp7pJGkeMhKA==} cpu: [x64] os: [linux] - '@rollup/rollup-win32-arm64-msvc@4.16.1': - resolution: {integrity: sha512-1vIP6Ce02L+qWD7uZYRiFiuAJo3m9kARatWmFSnss0gZnVj2Id7OPUU9gm49JPGasgcR3xMqiH3fqBJ8t00yVg==} + '@rollup/rollup-win32-arm64-msvc@4.29.1': + resolution: {integrity: sha512-F2OiJ42m77lSkizZQLuC+jiZ2cgueWQL5YC9tjo3AgaEw+KJmVxHGSyQfDUoYR9cci0lAywv2Clmckzulcq6ig==} cpu: [arm64] os: [win32] - '@rollup/rollup-win32-ia32-msvc@4.16.1': - resolution: {integrity: sha512-Y3M92DcVsT6LoP+wrKpoUWPaazaP1fzbNkp0a0ZSj5Y//+pQVfVe/tQdsYQQy7dwXR30ZfALUIc9PCh9Izir6w==} + '@rollup/rollup-win32-ia32-msvc@4.29.1': + resolution: {integrity: sha512-rYRe5S0FcjlOBZQHgbTKNrqxCBUmgDJem/VQTCcTnA2KCabYSWQDrytOzX7avb79cAAweNmMUb/Zw18RNd4mng==} cpu: [ia32] os: [win32] - '@rollup/rollup-win32-x64-msvc@4.16.1': - resolution: {integrity: sha512-x0fvpHMuF7fK5r8oZxSi8VYXkrVmRgubXpO/wcf15Lk3xZ4Jvvh5oG+u7Su1776A7XzVKZhD2eRc4t7H50gL3w==} + '@rollup/rollup-win32-x64-msvc@4.29.1': + resolution: {integrity: sha512-+10CMg9vt1MoHj6x1pxyjPSMjHTIlqs8/tBztXvPAx24SKs9jwVnKqHJumlH/IzhaPUaj3T6T6wfZr8okdXaIg==} cpu: [x64] os: [win32] @@ -1157,8 +1186,8 @@ packages: '@types/babel__traverse@7.17.1': resolution: {integrity: sha512-kVzjari1s2YVi77D3w1yuvohV2idweYXMCDzqBiVNN63TcDWrIlTVOYpqVrvbbyOE/IyzBoTKF0fdnLPEORFxA==} - '@types/estree@1.0.5': - resolution: {integrity: sha512-/kYRxGDLWzHOB7q+wtSUQlFrtcdUccpfy+X+9iMBpHK8QLLhx2wIPYuS5DYtR9Wa/YlZAbIovy7qVdB1Aq6Lyw==} + '@types/estree@1.0.6': + resolution: {integrity: sha512-AYnb1nQyY49te+VRAVgmzfcgjYS91mY5P0TKUDCLEM+gNnA+3T6rWITXRLYCpahpqSQbN5cE+gHpnPyXjHWxcw==} '@types/eventsource@1.1.15': resolution: {integrity: sha512-XQmGcbnxUNa06HR3VBVkc9+A2Vpi9ZyLJcdS5dwaQQ/4ZMWFO+5c90FnMUpbtMZwB/FChoYHwuVg8TvkECacTA==} @@ -1723,8 +1752,8 @@ packages: create-require@1.1.1: resolution: {integrity: sha512-dcKFX3jn0MpIaXjisoRvexIJVEKzaq7z2rZKxf+MSr9TkdmHmsU4m2lcLojrj/FHl8mk5VxMmYA+ftRkP/3oKQ==} - cross-spawn@7.0.3: - resolution: {integrity: sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w==} + cross-spawn@7.0.6: + resolution: {integrity: sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA==} engines: {node: '>= 8'} css-color-keywords@1.0.0: @@ -2109,6 +2138,7 @@ packages: eslint@8.57.0: resolution: {integrity: sha512-dZ6+mexnaTIbSBZWgou51U6OmzIhYM2VcNdtiTtI7qPNZm35Akpr0f6vtw3w1Kmn5PYo+tZVfh13WrhpS6oLqQ==} engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} + deprecated: This version is no longer supported. Please see https://eslint.org/version-support for other options. hasBin: true espree@9.6.1: @@ -2321,6 +2351,7 @@ packages: glob@7.2.3: resolution: {integrity: sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==} + deprecated: Glob versions prior to v9 are no longer supported globals@11.12.0: resolution: {integrity: sha512-WOBp/EEGUiIsJSp7wcv/y6MO+lV9UoncWqxuFfm8eBwzWNgyfBd6Gz+IeKQ9jCmyhoH99g15M3T+QaVHFjizVA==} @@ -2471,6 +2502,7 @@ packages: inflight@1.0.6: resolution: {integrity: sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA==} + deprecated: This module is not supported, and leaks memory. Do not use it. Check out lru-cache if you want a good and tested way to coalesce async requests by a key value, which is much more comprehensive and powerful. inherits@2.0.4: resolution: {integrity: sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==} @@ -2870,6 +2902,10 @@ packages: canvas: optional: true + jsep@1.4.0: + resolution: {integrity: sha512-B7qPcEVE3NVkmSJbaYxvv4cHkVW7DQsZz13pUMrfS8z8Q/BuShN+gcTXrUlPiGqM2/t/EEaI030bpxMqY8gMlw==} + engines: {node: '>= 10.16.0'} + jsesc@2.5.2: resolution: {integrity: sha512-OYu7XEzjkCQ3C5Ps3QIZsQfNpqoJyZZA99wd9aWd05NCtC5pWOkShK2mkL6HXQR6/Cy2lbNdPlZBpuQHXE63gA==} engines: {node: '>=4'} @@ -2910,15 +2946,15 @@ packages: jsonfile@6.1.0: resolution: {integrity: sha512-5dgndWOriYSm5cnYaJNhalLNDKOqFwyDB/rr1E9ZsGciGvKPs8R2xYGCacuf3z6K1YKDz182fd+fY3cn3pMqXQ==} + jsonpath-plus@10.0.7: + resolution: {integrity: sha512-GDA8d8fu9+s4QzAzo5LMGiLL/9YjecAX+ytlnqdeXYpU55qME57StDgaHt9R2pA7Dr8U31nwzxNJMJiHkrkRgw==} + engines: {node: '>=18.0.0'} + hasBin: true + jsonpath-plus@7.2.0: resolution: {integrity: sha512-zBfiUPM5nD0YZSBT/o/fbCUlCcepMIdP0CJZxM1+KgA4f2T206f6VAg9e7mX35+KlMaIc5qXW34f3BnwJ3w+RA==} engines: {node: '>=12.0.0'} - jsonpath-plus@8.1.0: - resolution: {integrity: sha512-qVTiuKztFGw0dGhYi3WNqvddx3/SHtyDT0xJaeyz4uP0d1tkpG+0y5uYQ4OcIo1TLAz3PE/qDOW9F0uDt3+CTw==} - engines: {node: '>=14.0.0'} - hasBin: true - jsx-ast-utils@3.3.5: resolution: {integrity: sha512-ZZow9HBI5O6EPgSJLUb8n2NKgmVWTwCvHGwFuJlMjvLFqlGG6pjirPhtdsseaLZjSibD8eegzmYpUZwoIlj2cQ==} engines: {node: '>=4.0'} @@ -3012,8 +3048,8 @@ packages: resolution: {integrity: sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==} engines: {node: '>= 8'} - micromatch@4.0.5: - resolution: {integrity: sha512-DMy+ERcEW2q8Z2Po+WNXuw3c5YaUSFjAO5GsJqfEl7UjvtIuFKO6ZrKvcItdy98dwFI2N1tg3zNIdKaQT+aNdA==} + micromatch@4.0.8: + resolution: {integrity: sha512-PXwfBhYu0hBCPw8Dn0E+WDYb7af3dSLVWKi3HGv84IdF4TyFoC0ysxFd0Goxw7nSv4T/PzEJQxsYsEiFCKo2BA==} engines: {node: '>=8.6'} mime-db@1.52.0: @@ -3064,8 +3100,8 @@ packages: mute-stream@0.0.8: resolution: {integrity: sha512-nnbWWOkoWyUsTjKrhgD0dcz22mdkSnpYqbEjIm2nhwhuxlSkpywJmBo8h0ZqJdkp73mb90SssHkN4rsRaBAfAA==} - nanoid@3.3.7: - resolution: {integrity: sha512-eSRppjcPIatRIMC1U6UngP8XFcz8MQWGQdt1MTBQ7NaAmvXDfvNxbvWV3x2y6CdEUciCSsDHDQZbhYaB8QEo2g==} + nanoid@3.3.8: + resolution: {integrity: sha512-WNLf5Sd8oZxOm+TzppcYk8gVOgP+l58xNy58D0nbUnOxOWRWvlcCV4kUF7ltmI6PsrLl/BgKEyS4mqsGChFN0w==} engines: {node: ^10 || ^12 || ^13.7 || ^14 || >=15.0.1} hasBin: true @@ -3491,6 +3527,7 @@ packages: rimraf@3.0.2: resolution: {integrity: sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==} + deprecated: Rimraf versions prior to v4 are no longer supported hasBin: true rimraf@5.0.5: @@ -3498,8 +3535,8 @@ packages: engines: {node: '>=14'} hasBin: true - rollup@4.16.1: - resolution: {integrity: sha512-5CaD3MPDlPKfhqzRvWXK96G6ELJfPZNb3LHiZxTHgDdC6jvwfGz2E8nY+9g1ONk4ttHsK1WaFP19Js4PSr1E3g==} + rollup@4.29.1: + resolution: {integrity: sha512-RaJ45M/kmJUzSWDs1Nnd5DdV4eerC98idtUOVr6FfKcgxqvjwHmxc5upLF9qZU9EpsVzzhleFahrT3shLuJzIw==} engines: {node: '>=18.0.0', npm: '>=8.0.0'} hasBin: true @@ -4009,8 +4046,8 @@ packages: vite: optional: true - vite@5.2.10: - resolution: {integrity: sha512-PAzgUZbP7msvQvqdSD+ErD5qGnSFiGOoWmV5yAKUEI0kdhjbH6nMWVyZQC/hSc4aXwc0oJ9aEdIiF9Oje0JFCw==} + vite@5.2.14: + resolution: {integrity: sha512-TFQLuwWLPms+NBNlh0D9LZQ+HXW471COABxw/9TEUBrjuHMo9BrYBPrN/SYAwIuVL+rLerycxiLT41t4f5MZpA==} engines: {node: ^18.0.0 || >=20.0.0} hasBin: true peerDependencies: @@ -4152,12 +4189,12 @@ packages: resolution: {integrity: sha512-7KxauUdBmSdWnmpaGFg+ppNjKF8uNLry8LyzjauQDOVONfFLNKrKvQOxZ/VuTIcS/gge/YNahf5RIIQWTSarlg==} engines: {node: ^12.13.0 || ^14.15.0 || >=16.0.0} - ws@8.8.0: - resolution: {integrity: sha512-JDAgSYQ1ksuwqfChJusw1LSJ8BizJ2e/vVu5Lxjq3YvNJNlROv1ui4i+c/kUUrPheBvQl4c5UbERhTwKa6QBJQ==} + ws@8.18.0: + resolution: {integrity: sha512-8VbfWfHLbbwu3+N6OKsOMpBdT4kXPDDB9cJk2bJ6mh9ucxdlnNvH1e+roYkKmN9Nxw2yjz7VzeO9oOz2zJ04Pw==} engines: {node: '>=10.0.0'} peerDependencies: bufferutil: ^4.0.1 - utf-8-validate: ^5.0.2 + utf-8-validate: '>=5.0.2' peerDependenciesMeta: bufferutil: optional: true @@ -4677,7 +4714,7 @@ snapshots: jest-util: 29.7.0 jest-validate: 29.7.0 jest-watcher: 29.7.0 - micromatch: 4.0.5 + micromatch: 4.0.8 pretty-format: 29.7.0 slash: 3.0.0 strip-ansi: 6.0.1 @@ -4799,7 +4836,7 @@ snapshots: jest-haste-map: 29.7.0 jest-regex-util: 29.6.3 jest-util: 29.7.0 - micromatch: 4.0.5 + micromatch: 4.0.8 pirates: 4.0.5 slash: 3.0.0 write-file-atomic: 4.0.2 @@ -4842,6 +4879,14 @@ snapshots: '@jridgewell/resolve-uri': 3.1.1 '@jridgewell/sourcemap-codec': 1.4.15 + '@jsep-plugin/assignment@1.3.0(jsep@1.4.0)': + dependencies: + jsep: 1.4.0 + + '@jsep-plugin/regex@1.0.4(jsep@1.4.0)': + dependencies: + jsep: 1.4.0 + '@lukeed/csprng@1.1.0': {} '@microsoft/fetch-event-source@2.0.1': {} @@ -4931,52 +4976,61 @@ snapshots: '@remix-run/router@1.16.0': {} - '@rollup/rollup-android-arm-eabi@4.16.1': + '@rollup/rollup-android-arm-eabi@4.29.1': + optional: true + + '@rollup/rollup-android-arm64@4.29.1': optional: true - '@rollup/rollup-android-arm64@4.16.1': + '@rollup/rollup-darwin-arm64@4.29.1': optional: true - '@rollup/rollup-darwin-arm64@4.16.1': + '@rollup/rollup-darwin-x64@4.29.1': optional: true - '@rollup/rollup-darwin-x64@4.16.1': + '@rollup/rollup-freebsd-arm64@4.29.1': optional: true - '@rollup/rollup-linux-arm-gnueabihf@4.16.1': + '@rollup/rollup-freebsd-x64@4.29.1': optional: true - '@rollup/rollup-linux-arm-musleabihf@4.16.1': + '@rollup/rollup-linux-arm-gnueabihf@4.29.1': optional: true - '@rollup/rollup-linux-arm64-gnu@4.16.1': + '@rollup/rollup-linux-arm-musleabihf@4.29.1': optional: true - '@rollup/rollup-linux-arm64-musl@4.16.1': + '@rollup/rollup-linux-arm64-gnu@4.29.1': optional: true - '@rollup/rollup-linux-powerpc64le-gnu@4.16.1': + '@rollup/rollup-linux-arm64-musl@4.29.1': optional: true - '@rollup/rollup-linux-riscv64-gnu@4.16.1': + '@rollup/rollup-linux-loongarch64-gnu@4.29.1': optional: true - '@rollup/rollup-linux-s390x-gnu@4.16.1': + '@rollup/rollup-linux-powerpc64le-gnu@4.29.1': optional: true - '@rollup/rollup-linux-x64-gnu@4.16.1': + '@rollup/rollup-linux-riscv64-gnu@4.29.1': optional: true - '@rollup/rollup-linux-x64-musl@4.16.1': + '@rollup/rollup-linux-s390x-gnu@4.29.1': optional: true - '@rollup/rollup-win32-arm64-msvc@4.16.1': + '@rollup/rollup-linux-x64-gnu@4.29.1': optional: true - '@rollup/rollup-win32-ia32-msvc@4.16.1': + '@rollup/rollup-linux-x64-musl@4.29.1': optional: true - '@rollup/rollup-win32-x64-msvc@4.16.1': + '@rollup/rollup-win32-arm64-msvc@4.29.1': + optional: true + + '@rollup/rollup-win32-ia32-msvc@4.29.1': + optional: true + + '@rollup/rollup-win32-x64-msvc@4.29.1': optional: true '@sinclair/typebox@0.27.8': {} @@ -5175,7 +5229,7 @@ snapshots: dependencies: '@babel/types': 7.23.9 - '@types/estree@1.0.5': {} + '@types/estree@1.0.6': {} '@types/eventsource@1.1.15': {} @@ -5366,10 +5420,10 @@ snapshots: '@ungap/structured-clone@1.2.0': {} - '@vitejs/plugin-react-swc@3.6.0(vite@5.2.10(@types/node@20.11.17)(sass@1.66.1))': + '@vitejs/plugin-react-swc@3.6.0(vite@5.2.14(@types/node@20.11.17)(sass@1.66.1))': dependencies: '@swc/core': 1.3.107 - vite: 5.2.10(@types/node@20.11.17)(sass@1.66.1) + vite: 5.2.14(@types/node@20.11.17)(sass@1.66.1) transitivePeerDependencies: - '@swc/helpers' @@ -5848,7 +5902,7 @@ snapshots: create-require@1.1.1: {} - cross-spawn@7.0.3: + cross-spawn@7.0.6: dependencies: path-key: 3.1.1 shebang-command: 2.0.0 @@ -6224,7 +6278,7 @@ snapshots: optionalDependencies: source-map: 0.6.1 - eslint-config-airbnb-base@15.0.0(eslint-plugin-import@2.29.1(@typescript-eslint/parser@6.21.0(eslint@8.57.0)(typescript@5.3.3))(eslint-import-resolver-typescript@3.6.1)(eslint@8.57.0))(eslint@8.57.0): + eslint-config-airbnb-base@15.0.0(eslint-plugin-import@2.29.1)(eslint@8.57.0): dependencies: confusing-browser-globals: 1.0.11 eslint: 8.57.0 @@ -6233,19 +6287,19 @@ snapshots: object.entries: 1.1.7 semver: 6.3.1 - eslint-config-airbnb-typescript@18.0.0(@typescript-eslint/eslint-plugin@6.21.0(@typescript-eslint/parser@6.21.0(eslint@8.57.0)(typescript@5.3.3))(eslint@8.57.0)(typescript@5.3.3))(@typescript-eslint/parser@6.21.0(eslint@8.57.0)(typescript@5.3.3))(eslint-plugin-import@2.29.1(@typescript-eslint/parser@6.21.0(eslint@8.57.0)(typescript@5.3.3))(eslint-import-resolver-typescript@3.6.1)(eslint@8.57.0))(eslint@8.57.0): + eslint-config-airbnb-typescript@18.0.0(@typescript-eslint/eslint-plugin@6.21.0(@typescript-eslint/parser@6.21.0(eslint@8.57.0)(typescript@5.3.3))(eslint@8.57.0)(typescript@5.3.3))(@typescript-eslint/parser@6.21.0(eslint@8.57.0)(typescript@5.3.3))(eslint-plugin-import@2.29.1)(eslint@8.57.0): dependencies: '@typescript-eslint/eslint-plugin': 6.21.0(@typescript-eslint/parser@6.21.0(eslint@8.57.0)(typescript@5.3.3))(eslint@8.57.0)(typescript@5.3.3) '@typescript-eslint/parser': 6.21.0(eslint@8.57.0)(typescript@5.3.3) eslint: 8.57.0 - eslint-config-airbnb-base: 15.0.0(eslint-plugin-import@2.29.1(@typescript-eslint/parser@6.21.0(eslint@8.57.0)(typescript@5.3.3))(eslint-import-resolver-typescript@3.6.1)(eslint@8.57.0))(eslint@8.57.0) + eslint-config-airbnb-base: 15.0.0(eslint-plugin-import@2.29.1)(eslint@8.57.0) transitivePeerDependencies: - eslint-plugin-import - eslint-config-airbnb@19.0.4(eslint-plugin-import@2.29.1(@typescript-eslint/parser@6.21.0(eslint@8.57.0)(typescript@5.3.3))(eslint-import-resolver-typescript@3.6.1)(eslint@8.57.0))(eslint-plugin-jsx-a11y@6.8.0(eslint@8.57.0))(eslint-plugin-react-hooks@4.6.0(eslint@8.57.0))(eslint-plugin-react@7.34.1(eslint@8.57.0))(eslint@8.57.0): + eslint-config-airbnb@19.0.4(eslint-plugin-import@2.29.1)(eslint-plugin-jsx-a11y@6.8.0(eslint@8.57.0))(eslint-plugin-react-hooks@4.6.0(eslint@8.57.0))(eslint-plugin-react@7.34.1(eslint@8.57.0))(eslint@8.57.0): dependencies: eslint: 8.57.0 - eslint-config-airbnb-base: 15.0.0(eslint-plugin-import@2.29.1(@typescript-eslint/parser@6.21.0(eslint@8.57.0)(typescript@5.3.3))(eslint-import-resolver-typescript@3.6.1)(eslint@8.57.0))(eslint@8.57.0) + eslint-config-airbnb-base: 15.0.0(eslint-plugin-import@2.29.1)(eslint@8.57.0) eslint-plugin-import: 2.29.1(@typescript-eslint/parser@6.21.0(eslint@8.57.0)(typescript@5.3.3))(eslint-import-resolver-typescript@3.6.1)(eslint@8.57.0) eslint-plugin-jsx-a11y: 6.8.0(eslint@8.57.0) eslint-plugin-react: 7.34.1(eslint@8.57.0) @@ -6270,7 +6324,7 @@ snapshots: debug: 4.3.4 enhanced-resolve: 5.15.0 eslint: 8.57.0 - eslint-module-utils: 2.8.0(@typescript-eslint/parser@6.21.0(eslint@8.57.0)(typescript@5.3.3))(eslint-import-resolver-node@0.3.9)(eslint-import-resolver-typescript@3.6.1(@typescript-eslint/parser@6.21.0(eslint@8.57.0)(typescript@5.3.3))(eslint-import-resolver-node@0.3.9)(eslint-plugin-import@2.29.1)(eslint@8.57.0))(eslint@8.57.0) + eslint-module-utils: 2.8.0(@typescript-eslint/parser@6.21.0(eslint@8.57.0)(typescript@5.3.3))(eslint-import-resolver-node@0.3.9)(eslint-import-resolver-typescript@3.6.1)(eslint@8.57.0) eslint-plugin-import: 2.29.1(@typescript-eslint/parser@6.21.0(eslint@8.57.0)(typescript@5.3.3))(eslint-import-resolver-typescript@3.6.1)(eslint@8.57.0) fast-glob: 3.3.2 get-tsconfig: 4.7.2 @@ -6282,7 +6336,7 @@ snapshots: - eslint-import-resolver-webpack - supports-color - eslint-module-utils@2.8.0(@typescript-eslint/parser@6.21.0(eslint@8.57.0)(typescript@5.3.3))(eslint-import-resolver-node@0.3.9)(eslint-import-resolver-typescript@3.6.1(@typescript-eslint/parser@6.21.0(eslint@8.57.0)(typescript@5.3.3))(eslint-import-resolver-node@0.3.9)(eslint-plugin-import@2.29.1)(eslint@8.57.0))(eslint@8.57.0): + eslint-module-utils@2.8.0(@typescript-eslint/parser@6.21.0(eslint@8.57.0)(typescript@5.3.3))(eslint-import-resolver-node@0.3.9)(eslint-import-resolver-typescript@3.6.1)(eslint@8.57.0): dependencies: debug: 3.2.7 optionalDependencies: @@ -6303,7 +6357,7 @@ snapshots: doctrine: 2.1.0 eslint: 8.57.0 eslint-import-resolver-node: 0.3.9 - eslint-module-utils: 2.8.0(@typescript-eslint/parser@6.21.0(eslint@8.57.0)(typescript@5.3.3))(eslint-import-resolver-node@0.3.9)(eslint-import-resolver-typescript@3.6.1(@typescript-eslint/parser@6.21.0(eslint@8.57.0)(typescript@5.3.3))(eslint-import-resolver-node@0.3.9)(eslint-plugin-import@2.29.1)(eslint@8.57.0))(eslint@8.57.0) + eslint-module-utils: 2.8.0(@typescript-eslint/parser@6.21.0(eslint@8.57.0)(typescript@5.3.3))(eslint-import-resolver-node@0.3.9)(eslint-import-resolver-typescript@3.6.1)(eslint@8.57.0) hasown: 2.0.0 is-core-module: 2.13.1 is-glob: 4.0.3 @@ -6402,7 +6456,7 @@ snapshots: '@ungap/structured-clone': 1.2.0 ajv: 6.12.6 chalk: 4.1.2 - cross-spawn: 7.0.3 + cross-spawn: 7.0.6 debug: 4.3.4 doctrine: 3.0.0 escape-string-regexp: 4.0.0 @@ -6455,7 +6509,7 @@ snapshots: execa@5.1.1: dependencies: - cross-spawn: 7.0.3 + cross-spawn: 7.0.6 get-stream: 6.0.1 human-signals: 2.1.0 is-stream: 2.0.1 @@ -6491,7 +6545,7 @@ snapshots: '@nodelib/fs.walk': 1.2.8 glob-parent: 5.1.2 merge2: 1.4.1 - micromatch: 4.0.5 + micromatch: 4.0.8 fast-json-stable-stringify@2.1.0: {} @@ -6565,7 +6619,7 @@ snapshots: foreground-child@3.1.1: dependencies: - cross-spawn: 7.0.3 + cross-spawn: 7.0.6 signal-exit: 4.1.0 form-data@4.0.0: @@ -7118,7 +7172,7 @@ snapshots: jest-runner: 29.7.0 jest-util: 29.7.0 jest-validate: 29.7.0 - micromatch: 4.0.5 + micromatch: 4.0.8 parse-json: 5.2.0 pretty-format: 29.7.0 slash: 3.0.0 @@ -7186,7 +7240,7 @@ snapshots: jest-regex-util: 29.6.3 jest-util: 29.7.0 jest-worker: 29.7.0 - micromatch: 4.0.5 + micromatch: 4.0.8 walker: 1.0.8 optionalDependencies: fsevents: 2.3.3 @@ -7210,7 +7264,7 @@ snapshots: '@types/stack-utils': 2.0.1 chalk: 4.1.2 graceful-fs: 4.2.10 - micromatch: 4.0.5 + micromatch: 4.0.8 pretty-format: 29.6.3 slash: 3.0.0 stack-utils: 2.0.5 @@ -7222,7 +7276,7 @@ snapshots: '@types/stack-utils': 2.0.1 chalk: 4.1.2 graceful-fs: 4.2.10 - micromatch: 4.0.5 + micromatch: 4.0.8 pretty-format: 29.7.0 slash: 3.0.0 stack-utils: 2.0.5 @@ -7462,13 +7516,15 @@ snapshots: whatwg-encoding: 2.0.0 whatwg-mimetype: 3.0.0 whatwg-url: 11.0.0 - ws: 8.8.0 + ws: 8.18.0 xml-name-validator: 4.0.0 transitivePeerDependencies: - bufferutil - supports-color - utf-8-validate + jsep@1.4.0: {} + jsesc@2.5.2: {} json-parse-even-better-errors@2.3.1: {} @@ -7504,9 +7560,13 @@ snapshots: optionalDependencies: graceful-fs: 4.2.10 - jsonpath-plus@7.2.0: {} + jsonpath-plus@10.0.7: + dependencies: + '@jsep-plugin/assignment': 1.3.0(jsep@1.4.0) + '@jsep-plugin/regex': 1.0.4(jsep@1.4.0) + jsep: 1.4.0 - jsonpath-plus@8.1.0: {} + jsonpath-plus@7.2.0: {} jsx-ast-utils@3.3.5: dependencies: @@ -7588,7 +7648,7 @@ snapshots: merge2@1.4.1: {} - micromatch@4.0.5: + micromatch@4.0.8: dependencies: braces: 3.0.3 picomatch: 2.3.1 @@ -7627,7 +7687,7 @@ snapshots: mute-stream@0.0.8: {} - nanoid@3.3.7: {} + nanoid@3.3.8: {} natural-compare@1.4.0: {} @@ -7821,13 +7881,13 @@ snapshots: postcss@8.4.31: dependencies: - nanoid: 3.3.7 + nanoid: 3.3.8 picocolors: 1.0.0 source-map-js: 1.0.2 postcss@8.4.38: dependencies: - nanoid: 3.3.7 + nanoid: 3.3.8 picocolors: 1.0.0 source-map-js: 1.2.0 @@ -8055,26 +8115,29 @@ snapshots: dependencies: glob: 10.3.12 - rollup@4.16.1: + rollup@4.29.1: dependencies: - '@types/estree': 1.0.5 + '@types/estree': 1.0.6 optionalDependencies: - '@rollup/rollup-android-arm-eabi': 4.16.1 - '@rollup/rollup-android-arm64': 4.16.1 - '@rollup/rollup-darwin-arm64': 4.16.1 - '@rollup/rollup-darwin-x64': 4.16.1 - '@rollup/rollup-linux-arm-gnueabihf': 4.16.1 - '@rollup/rollup-linux-arm-musleabihf': 4.16.1 - '@rollup/rollup-linux-arm64-gnu': 4.16.1 - '@rollup/rollup-linux-arm64-musl': 4.16.1 - '@rollup/rollup-linux-powerpc64le-gnu': 4.16.1 - '@rollup/rollup-linux-riscv64-gnu': 4.16.1 - '@rollup/rollup-linux-s390x-gnu': 4.16.1 - '@rollup/rollup-linux-x64-gnu': 4.16.1 - '@rollup/rollup-linux-x64-musl': 4.16.1 - '@rollup/rollup-win32-arm64-msvc': 4.16.1 - '@rollup/rollup-win32-ia32-msvc': 4.16.1 - '@rollup/rollup-win32-x64-msvc': 4.16.1 + '@rollup/rollup-android-arm-eabi': 4.29.1 + '@rollup/rollup-android-arm64': 4.29.1 + '@rollup/rollup-darwin-arm64': 4.29.1 + '@rollup/rollup-darwin-x64': 4.29.1 + '@rollup/rollup-freebsd-arm64': 4.29.1 + '@rollup/rollup-freebsd-x64': 4.29.1 + '@rollup/rollup-linux-arm-gnueabihf': 4.29.1 + '@rollup/rollup-linux-arm-musleabihf': 4.29.1 + '@rollup/rollup-linux-arm64-gnu': 4.29.1 + '@rollup/rollup-linux-arm64-musl': 4.29.1 + '@rollup/rollup-linux-loongarch64-gnu': 4.29.1 + '@rollup/rollup-linux-powerpc64le-gnu': 4.29.1 + '@rollup/rollup-linux-riscv64-gnu': 4.29.1 + '@rollup/rollup-linux-s390x-gnu': 4.29.1 + '@rollup/rollup-linux-x64-gnu': 4.29.1 + '@rollup/rollup-linux-x64-musl': 4.29.1 + '@rollup/rollup-win32-arm64-msvc': 4.29.1 + '@rollup/rollup-win32-ia32-msvc': 4.29.1 + '@rollup/rollup-win32-x64-msvc': 4.29.1 fsevents: 2.3.3 run-async@2.4.1: {} @@ -8583,7 +8646,7 @@ snapshots: '@types/istanbul-lib-coverage': 2.0.3 convert-source-map: 1.7.0 - vite-plugin-checker@0.6.4(eslint@8.57.0)(optionator@0.9.3)(typescript@5.3.3)(vite@5.2.10(@types/node@20.11.17)(sass@1.66.1)): + vite-plugin-checker@0.6.4(eslint@8.57.0)(optionator@0.9.3)(typescript@5.3.3)(vite@5.2.14(@types/node@20.11.17)(sass@1.66.1)): dependencies: '@babel/code-frame': 7.23.5 ansi-escapes: 4.3.2 @@ -8596,7 +8659,7 @@ snapshots: semver: 7.5.4 strip-ansi: 6.0.1 tiny-invariant: 1.3.3 - vite: 5.2.10(@types/node@20.11.17)(sass@1.66.1) + vite: 5.2.14(@types/node@20.11.17)(sass@1.66.1) vscode-languageclient: 7.0.0 vscode-languageserver: 7.0.0 vscode-languageserver-textdocument: 1.0.11 @@ -8606,27 +8669,27 @@ snapshots: optionator: 0.9.3 typescript: 5.3.3 - vite-plugin-ejs@1.7.0(vite@5.2.10(@types/node@20.11.17)(sass@1.66.1)): + vite-plugin-ejs@1.7.0(vite@5.2.14(@types/node@20.11.17)(sass@1.66.1)): dependencies: ejs: 3.1.10 - vite: 5.2.10(@types/node@20.11.17)(sass@1.66.1) + vite: 5.2.14(@types/node@20.11.17)(sass@1.66.1) - vite-tsconfig-paths@4.3.2(typescript@5.3.3)(vite@5.2.10(@types/node@20.11.17)(sass@1.66.1)): + vite-tsconfig-paths@4.3.2(typescript@5.3.3)(vite@5.2.14(@types/node@20.11.17)(sass@1.66.1)): dependencies: debug: 4.3.4 globrex: 0.1.2 tsconfck: 3.0.3(typescript@5.3.3) optionalDependencies: - vite: 5.2.10(@types/node@20.11.17)(sass@1.66.1) + vite: 5.2.14(@types/node@20.11.17)(sass@1.66.1) transitivePeerDependencies: - supports-color - typescript - vite@5.2.10(@types/node@20.11.17)(sass@1.66.1): + vite@5.2.14(@types/node@20.11.17)(sass@1.66.1): dependencies: esbuild: 0.20.2 postcss: 8.4.38 - rollup: 4.16.1 + rollup: 4.29.1 optionalDependencies: '@types/node': 20.11.17 fsevents: 2.3.3 @@ -8778,7 +8841,7 @@ snapshots: imurmurhash: 0.1.4 signal-exit: 3.0.7 - ws@8.8.0: {} + ws@8.18.0: {} xml-name-validator@4.0.0: {} diff --git a/pom.xml b/pom.xml index d631e7751..43427b3f1 100644 --- a/pom.xml +++ b/pom.xml @@ -35,11 +35,10 @@ 3.25.3 1.11.4 1.14.19 - 7.4.4 + 7.8.0 3.1.0 3.0.13 2.14.0 - 3.8.0 1.6.2 1.18.34 3.25.5