From bcd266fd588668bac37fb5cd9d6e1e4697d19252 Mon Sep 17 00:00:00 2001 From: Aleksander <170264518+t-aleksander@users.noreply.github.com> Date: Mon, 19 Jan 2026 12:07:49 +0100 Subject: [PATCH 1/5] send logs from proxy --- Cargo.lock | 7 +++-- Cargo.toml | 1 + src/grpc.rs | 10 +------ src/http.rs | 28 +++++++------------- src/lib.rs | 4 +++ src/logging.rs | 71 +++++++++++++++++++++++++++++++++++++++++++++++--- src/main.rs | 11 ++++++-- src/setup.rs | 34 +++++++++++++++++++++--- 8 files changed, 127 insertions(+), 39 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 96128fbf..22718c5b 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -390,12 +390,14 @@ checksum = "613afe47fcd5fac7ccf1db93babcb082c5994d996f20b8b159f2ad1658eb5724" [[package]] name = "chrono" -version = "0.4.42" +version = "0.4.43" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "145052bdd345b87320e369255277e3fb5152762ad123a901ef5c262dd38fe8d2" +checksum = "fac4744fb15ae8337dc853fee7fb3f4e48c0fbaa23d0afe49c447b4fab126118" dependencies = [ "iana-time-zone", + "js-sys", "num-traits", + "wasm-bindgen", "windows-link", ] @@ -667,6 +669,7 @@ dependencies = [ "axum-client-ip", "axum-extra", "base64", + "chrono", "clap", "defguard_certs", "defguard_version", diff --git a/Cargo.toml b/Cargo.toml index 76154ffe..36f5765d 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -53,6 +53,7 @@ base64 = "0.22" tower = "0.5" futures-util = "0.3" ammonia = "4.1.1" +chrono = "0.4" [build-dependencies] tonic-prost-build = "0.14" diff --git a/src/grpc.rs b/src/grpc.rs index 3dd2c21d..fcb4feea 100644 --- a/src/grpc.rs +++ b/src/grpc.rs @@ -24,7 +24,6 @@ use tracing::Instrument; use crate::{ error::ApiError, - http::GRPC_SERVER_RESTART_CHANNEL, proto::{core_request, core_response, proxy_server, CoreRequest, CoreResponse, DeviceInfo}, MIN_CORE_VERSION, VERSION, }; @@ -45,7 +44,6 @@ pub(crate) struct ProxyServer { pub(crate) connected: Arc, pub(crate) core_version: Arc>>, config: Arc>>, - setup_in_progress: Arc, } impl ProxyServer { @@ -59,7 +57,6 @@ impl ProxyServer { connected: Arc::new(AtomicBool::new(false)), core_version: Arc::new(Mutex::new(None)), config: Arc::new(Mutex::new(None)), - setup_in_progress: Arc::new(AtomicBool::new(false)), } } @@ -118,11 +115,7 @@ impl ProxyServer { builder .add_service(versioned_service) - .serve_with_shutdown(addr, async move { - let mut rx_lock = GRPC_SERVER_RESTART_CHANNEL.1.lock().await; - rx_lock.recv().await; - info!("Shutting down gRPC server for restart..."); - }) + .serve(addr) .await .map_err(|err| { error!("gRPC server error: {err}"); @@ -190,7 +183,6 @@ impl Clone for ProxyServer { connected: Arc::clone(&self.connected), core_version: Arc::clone(&self.core_version), config: Arc::clone(&self.config), - setup_in_progress: Arc::clone(&self.setup_in_progress), } } } diff --git a/src/http.rs b/src/http.rs index f18d52d3..c1eedced 100644 --- a/src/http.rs +++ b/src/http.rs @@ -3,7 +3,7 @@ use std::{ fs::read_to_string, net::{IpAddr, Ipv4Addr, SocketAddr}, path::Path, - sync::{atomic::Ordering, Arc, LazyLock}, + sync::{atomic::Ordering, Arc}, time::Duration, }; @@ -20,11 +20,7 @@ use axum_extra::extract::cookie::Key; use clap::crate_version; use defguard_version::{server::DefguardVersionLayer, Version}; use serde::Serialize; -use tokio::{ - net::TcpListener, - sync::{oneshot, Mutex}, - task::JoinSet, -}; +use tokio::{net::TcpListener, sync::oneshot, task::JoinSet}; use tower_governor::{ governor::GovernorConfigBuilder, key_extractor::SmartIpKeyExtractor, GovernorLayer, }; @@ -40,7 +36,7 @@ use crate::{ grpc::{Configuration, ProxyServer}, handlers::{desktop_client_mfa, enrollment, password_reset, polling}, setup::ProxySetupServer, - CommsChannel, VERSION, + LogsReceiver, VERSION, }; pub(crate) static ENROLLMENT_COOKIE_NAME: &str = "defguard_proxy"; @@ -50,13 +46,8 @@ const DEFGUARD_CORE_VERSION_HEADER: &str = "defguard-core-version"; const RATE_LIMITER_CLEANUP_PERIOD: Duration = Duration::from_secs(60); const X_FORWARDED_FOR: &str = "x-forwarded-for"; const X_POWERED_BY: &str = "x-powered-by"; -const GRPC_CERT_NAME: &str = "proxy_grpc_cert.pem"; -const GRPC_KEY_NAME: &str = "proxy_grpc_key.pem"; - -pub static GRPC_SERVER_RESTART_CHANNEL: LazyLock> = LazyLock::new(|| { - let (tx, rx) = tokio::sync::mpsc::channel(100); - (Arc::new(Mutex::new(tx)), Arc::new(Mutex::new(rx))) -}); +pub(crate) const GRPC_CERT_NAME: &str = "proxy_grpc_cert.pem"; +pub(crate) const GRPC_KEY_NAME: &str = "proxy_grpc_key.pem"; #[derive(Clone)] pub(crate) struct AppState { @@ -173,7 +164,7 @@ async fn powered_by_header(mut response: Response) -> Response { response } -pub async fn run_server(config: Config) -> anyhow::Result<()> { +pub async fn run_server(config: Config, logs_rx: LogsReceiver) -> anyhow::Result<()> { info!("Starting Defguard Proxy server"); debug!("Using config: {config:?}"); @@ -193,7 +184,7 @@ pub async fn run_server(config: Config) -> anyhow::Result<()> { let server_clone = grpc_server.clone(); - let setup_server = ProxySetupServer::new(); + let setup_server = ProxySetupServer::new(logs_rx.clone()); // Start gRPC server. // TODO: Wait with spawning the HTTP server until gRPC server is ready. @@ -205,6 +196,7 @@ pub async fn run_server(config: Config) -> anyhow::Result<()> { } loop { + info!("Starting gRPC server..."); let server_to_run = server_clone.clone(); if let (Some(cert), Some(key)) = ( @@ -219,11 +211,11 @@ pub async fn run_server(config: Config) -> anyhow::Result<()> { } else if !server_clone.setup_completed() { // Only attempt setup if not already configured info!( - "No gRPC TLS certificates found at {}, new certificates will be generated", + "No gRPC TLS certificates found at {}, new certificates will be obtained during setup", cert_dir.display() ); let configuration = setup_server - .await_setup(SocketAddr::new( + .await_initial_setup(SocketAddr::new( config .grpc_bind_address .unwrap_or(IpAddr::V4(Ipv4Addr::UNSPECIFIED)), diff --git a/src/lib.rs b/src/lib.rs index a9e22f5c..c87e0274 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -3,6 +3,8 @@ use std::sync::Arc; use defguard_version::Version; use tokio::sync::mpsc; +use crate::proto::LogEntry; + pub mod assets; pub mod config; mod enterprise; @@ -27,3 +29,5 @@ type CommsChannel = ( Arc>>, Arc>>, ); + +type LogsReceiver = Arc>>; diff --git a/src/logging.rs b/src/logging.rs index 13929a0b..44c0c88c 100644 --- a/src/logging.rs +++ b/src/logging.rs @@ -8,6 +8,7 @@ use defguard_version::{ ComponentInfo, DefguardVersionError, Version, }; use log::LevelFilter; +use tokio::sync::mpsc::Sender; use tracing::{Event, Level, Subscriber}; use tracing_subscriber::{ fmt::{ @@ -19,18 +20,25 @@ use tracing_subscriber::{ layer::SubscriberExt, registry::LookupSpan, util::SubscriberInitExt, - EnvFilter, + EnvFilter, Layer, }; +use crate::proto::LogEntry; + // Initializes tracing with the specified log level and version information. // Allows fine-grained filtering with `EnvFilter` directives. // The directives are read from `DEFGUARD_PROXY_LOG_FILTER` env variable. // For more info read: -pub fn init_tracing(own_version: Version, level: &LevelFilter) -> Result<(), DefguardVersionError> { +pub fn init_tracing( + own_version: Version, + level: &LevelFilter, + logs_tx: Sender, +) -> Result<(), DefguardVersionError> { tracing_subscriber::registry() .with( - EnvFilter::try_from_env("DEFGUARD_PROXY_LOG_FILTER") - .unwrap_or_else(|_| level.to_string().into()), + EnvFilter::try_from_env("DEFGUARD_PROXY_LOG_FILTER").unwrap_or_else(|_| { + format!("{level},h2=warn,h2::codec=off,tower=warn,hyper=warn").into() + }), ) .with(VersionFieldLayer) .with( @@ -38,6 +46,7 @@ pub fn init_tracing(own_version: Version, level: &LevelFilter) -> Result<(), Def .event_format(HttpVersionFormatter::new(own_version)) .fmt_fields(VersionFilteredFields), ) + .with(GrpcLogLayer::new(logs_tx)) .init(); info!("Tracing initialized"); @@ -157,3 +166,57 @@ where writeln!(versioned_writer) } } + +/// A tracing layer that sends log entries to a gRPC logs channel. +pub struct GrpcLogLayer { + logs_tx: Sender, +} + +impl GrpcLogLayer { + #[must_use] + pub const fn new(logs_tx: Sender) -> Self { + Self { logs_tx } + } +} + +impl Layer for GrpcLogLayer +where + S: Subscriber, +{ + fn on_event(&self, event: &Event<'_>, _ctx: tracing_subscriber::layer::Context<'_, S>) { + if self.logs_tx.is_closed() { + return; + } + + let mut visitor = LogVisitor::default(); + event.record(&mut visitor); + + let entry = LogEntry { + level: format!("{:?}", event.metadata().level()), + target: event.metadata().target().to_string(), + message: visitor.message, + timestamp: chrono::Utc::now().to_rfc3339(), + fields: visitor.fields, + }; + + // Drop the buffer overflow error for now + let _ = self.logs_tx.try_send(entry); + } +} + +#[derive(Default)] +struct LogVisitor { + message: String, + fields: std::collections::HashMap, +} + +impl tracing::field::Visit for LogVisitor { + fn record_debug(&mut self, field: &tracing::field::Field, value: &dyn std::fmt::Debug) { + if field.name() == "message" { + self.message = format!("{value:?}"); + } else { + self.fields + .insert(field.name().to_string(), format!("{value:?}")); + } + } +} diff --git a/src/main.rs b/src/main.rs index 0c3ef877..a7e06d84 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,5 +1,8 @@ +use std::sync::Arc; + use defguard_proxy::{config::get_config, http::run_server, logging::init_tracing, VERSION}; use defguard_version::Version; +use tokio::sync::mpsc; #[tokio::main] async fn main() -> anyhow::Result<()> { @@ -8,13 +11,17 @@ async fn main() -> anyhow::Result<()> { dotenvy::dotenv().ok(); } + // TODO: The channel size may need to be adjusted or some other approach should be used + // to avoid dropping log messages. + let (logs_tx, logs_rx) = mpsc::channel(200); + let config = get_config()?; - init_tracing(Version::parse(VERSION)?, &config.log_level)?; + init_tracing(Version::parse(VERSION)?, &config.log_level, logs_tx)?; // read config from env tracing::info!("Starting ... version v{}", VERSION); // run API web server - run_server(config).await?; + run_server(config, Arc::new(tokio::sync::Mutex::new(logs_rx))).await?; Ok(()) } diff --git a/src/setup.rs b/src/setup.rs index 437ac81f..51189d3b 100644 --- a/src/setup.rs +++ b/src/setup.rs @@ -11,13 +11,14 @@ use defguard_version::{ DefguardComponent, Version, }; use tokio::sync::mpsc; +use tokio_stream::wrappers::UnboundedReceiverStream; use tonic::{transport::Server, Request, Response, Status}; use crate::{ error::ApiError, grpc::Configuration, - proto::{proxy_setup_server, DerPayload, InitialSetupInfo}, - CommsChannel, MIN_CORE_VERSION, VERSION, + proto::{proxy_setup_server, DerPayload, InitialSetupInfo, LogEntry}, + CommsChannel, LogsReceiver, MIN_CORE_VERSION, VERSION, }; static SETUP_CHANNEL: LazyLock>> = LazyLock::new(|| { @@ -31,6 +32,7 @@ static SETUP_CHANNEL: LazyLock>> = LazyLock:: pub(crate) struct ProxySetupServer { setup_in_progress: Arc, key_pair: Arc>>, + logs_rx: LogsReceiver, } impl Clone for ProxySetupServer { @@ -38,15 +40,17 @@ impl Clone for ProxySetupServer { Self { setup_in_progress: Arc::clone(&self.setup_in_progress), key_pair: Arc::clone(&self.key_pair), + logs_rx: Arc::clone(&self.logs_rx), } } } impl ProxySetupServer { - pub fn new() -> Self { + pub fn new(logs_rx: LogsReceiver) -> Self { Self { setup_in_progress: Arc::new(AtomicBool::new(false)), key_pair: Arc::new(Mutex::new(None)), + logs_rx, } } @@ -54,7 +58,7 @@ impl ProxySetupServer { /// Spins up a dedicated temporary gRPC server over HTTP to handle the setup process. /// The setup process involves generating a CSR, sending it to Core and receiving signed TLS certificates. /// Returns the received gRPC configuration (locally generated key pair and remotely signed certificate) upon successful setup. - pub(crate) async fn await_setup( + pub(crate) async fn await_initial_setup( &self, addr: SocketAddr, ) -> Result { @@ -109,6 +113,8 @@ impl ProxySetupServer { #[tonic::async_trait] impl proxy_setup_server::ProxySetup for ProxySetupServer { + type ReadLogsStream = UnboundedReceiverStream>; + async fn start( &self, request: Request, @@ -213,4 +219,24 @@ impl proxy_setup_server::ProxySetup for ProxySetupServer { Ok(Response::new(())) } + + async fn read_logs( + &self, + _request: Request<()>, + ) -> Result, Status> { + let logs_rx = self.logs_rx.clone(); + + let (tx, rx) = mpsc::unbounded_channel(); + + tokio::spawn(async move { + while let Some(log_entry) = logs_rx.lock().await.recv().await { + if let Err(e) = tx.send(Ok(log_entry)) { + debug!("Failed to send log entry to gRPC stream: receiver disconnected ({e})",); + break; + } + } + }); + + Ok(Response::new(UnboundedReceiverStream::new(rx))) + } } From 48134f2a721c5be9e1d9140d2ee4a616e0053e1b Mon Sep 17 00:00:00 2001 From: Aleksander <170264518+t-aleksander@users.noreply.github.com> Date: Sun, 25 Jan 2026 17:55:57 +0100 Subject: [PATCH 2/5] proxy wizard --- src/config.rs | 8 +- src/grpc.rs | 17 +--- src/http.rs | 121 +++++++++++++-------------- src/lib.rs | 2 +- src/logging.rs | 15 ++-- src/main.rs | 53 ++++++++++-- src/setup.rs | 217 +++++++++++++++++++++++++++++++++++++++---------- 7 files changed, 294 insertions(+), 139 deletions(-) diff --git a/src/config.rs b/src/config.rs index 6a1e9e0d..2cc5f883 100644 --- a/src/config.rs +++ b/src/config.rs @@ -11,7 +11,7 @@ fn default_url() -> Url { #[derive(Parser, Debug, Deserialize)] #[command(version)] -pub struct Config { +pub struct EnvConfig { // port the API server will listen on #[arg( long, @@ -77,15 +77,15 @@ pub enum ConfigError { ParseError(#[from] toml::de::Error), } -pub fn get_config() -> Result { +pub fn get_env_config() -> Result { // parse CLI arguments to get config file path - let cli_config = Config::parse(); + let cli_config = EnvConfig::parse(); // load config from file if one was specified if let Some(config_path) = cli_config.config_path { info!("Reading configuration from file: {config_path:?}"); let config_toml = read_to_string(config_path)?; - let file_config: Config = toml::from_str(&config_toml)?; + let file_config: EnvConfig = toml::from_str(&config_toml)?; Ok(file_config) } else { Ok(cli_config) diff --git a/src/grpc.rs b/src/grpc.rs index adbddb24..e1af1594 100644 --- a/src/grpc.rs +++ b/src/grpc.rs @@ -34,9 +34,9 @@ type ClientMap = HashMap Result<(), ApiError> { - let mut lock = self - .config - .lock() - .expect("Failed to acquire lock on config mutex when updating TLS configuration"); - let config = lock.get_or_insert_with(Configuration::default); - config.grpc_cert_pem = cert_pem; - config.grpc_key_pem = key_pem; - Ok(()) - } - pub(crate) fn configure(&self, config: Configuration) { let mut lock = self .config diff --git a/src/http.rs b/src/http.rs index f431a037..e0563850 100644 --- a/src/http.rs +++ b/src/http.rs @@ -1,6 +1,5 @@ use std::{ collections::HashMap, - fs::read_to_string, net::{IpAddr, Ipv4Addr, SocketAddr}, path::Path, sync::{atomic::Ordering, Arc}, @@ -22,7 +21,7 @@ use defguard_version::{server::DefguardVersionLayer, Version}; use serde::Serialize; use tokio::{ net::TcpListener, - sync::{mpsc, oneshot, Mutex}, + sync::{mpsc, oneshot}, task::JoinSet, }; use tower_governor::{ @@ -34,7 +33,7 @@ use url::Url; use crate::{ assets::{index, web_asset}, - config::Config, + config::EnvConfig, enterprise::handlers::openid_login::{self, FlowType}, error::ApiError, grpc::{Configuration, ProxyServer}, @@ -50,8 +49,8 @@ const DEFGUARD_CORE_VERSION_HEADER: &str = "defguard-core-version"; const RATE_LIMITER_CLEANUP_PERIOD: Duration = Duration::from_secs(60); const X_FORWARDED_FOR: &str = "x-forwarded-for"; const X_POWERED_BY: &str = "x-powered-by"; -pub(crate) const GRPC_CERT_NAME: &str = "proxy_grpc_cert.pem"; -pub(crate) const GRPC_KEY_NAME: &str = "proxy_grpc_key.pem"; +pub const GRPC_CERT_NAME: &str = "proxy_grpc_cert.pem"; +pub const GRPC_KEY_NAME: &str = "proxy_grpc_key.pem"; #[derive(Clone)] pub(crate) struct AppState { @@ -168,9 +167,48 @@ async fn powered_by_header(mut response: Response) -> Response { response } -pub async fn run_server(config: Config, logs_rx: LogsReceiver) -> anyhow::Result<()> { +pub async fn run_setup( + env_config: &EnvConfig, + logs_rx: LogsReceiver, +) -> anyhow::Result { + let setup_server = ProxySetupServer::new(logs_rx); + let cert_dir = Path::new(&env_config.cert_dir); + if !cert_dir.exists() { + tokio::fs::create_dir_all(cert_dir).await?; + } + + // Only attempt setup if not already configured + info!( + "No gRPC TLS certificates found at {}, new certificates will be obtained during setup", + cert_dir.display() + ); + let configuration = setup_server + .await_initial_setup(SocketAddr::new( + env_config + .grpc_bind_address + .unwrap_or(IpAddr::V4(Ipv4Addr::UNSPECIFIED)), + env_config.grpc_port, + )) + .await?; + info!("Generated new gRPC TLS certificates and signed by Defguard Core"); + + let Configuration { + grpc_cert_pem, + grpc_key_pem, + .. + } = &configuration; + + let cert_path = cert_dir.join(GRPC_CERT_NAME); + let key_path = cert_dir.join(GRPC_KEY_NAME); + tokio::fs::write(&cert_path, grpc_cert_pem).await?; + tokio::fs::write(&key_path, grpc_key_pem).await?; + + Ok(configuration) +} + +pub async fn run_server(env_config: EnvConfig, config: Configuration) -> anyhow::Result<()> { info!("Starting Defguard Proxy server"); - debug!("Using config: {config:?}"); + debug!("Using config: {env_config:?}"); let mut tasks = JoinSet::new(); @@ -180,70 +218,21 @@ pub async fn run_server(config: Config, logs_rx: LogsReceiver) -> anyhow::Result // connect to upstream gRPC server let grpc_server = ProxyServer::new(tx); - let server_clone = grpc_server.clone(); - - let setup_server = ProxySetupServer::new(logs_rx.clone()); + grpc_server.configure(config); // Start gRPC server. // TODO: Wait with spawning the HTTP server until gRPC server is ready. debug!("Spawning gRPC server"); tasks.spawn(async move { - let cert_dir = Path::new(&config.cert_dir); - if !cert_dir.exists() { - tokio::fs::create_dir_all(cert_dir).await?; - } - loop { info!("Starting gRPC server..."); let server_to_run = server_clone.clone(); - - if let (Some(cert), Some(key)) = ( - read_to_string(cert_dir.join(GRPC_CERT_NAME)).ok(), - read_to_string(cert_dir.join(GRPC_KEY_NAME)).ok(), - ) { - info!( - "Using existing gRPC TLS certificates from {}", - cert_dir.display() - ); - server_clone.set_tls_config(cert, key)?; - } else if !server_clone.setup_completed() { - // Only attempt setup if not already configured - info!( - "No gRPC TLS certificates found at {}, new certificates will be obtained during setup", - cert_dir.display() - ); - let configuration = setup_server - .await_initial_setup(SocketAddr::new( - config - .grpc_bind_address - .unwrap_or(IpAddr::V4(Ipv4Addr::UNSPECIFIED)), - config.grpc_port, - )) - .await?; - info!("Generated new gRPC TLS certificates and signed by Defguard Core"); - - let Configuration { - grpc_cert_pem, - grpc_key_pem, - .. - } = &configuration; - - let cert_path = cert_dir.join(GRPC_CERT_NAME); - let key_path = cert_dir.join(GRPC_KEY_NAME); - tokio::fs::write(&cert_path, grpc_cert_pem).await?; - tokio::fs::write(&key_path, grpc_key_pem).await?; - - server_to_run.configure(configuration); - } else { - info!("Proxy already configured, skipping setup phase"); - } - let addr = SocketAddr::new( - config + env_config .grpc_bind_address .unwrap_or(IpAddr::V4(Ipv4Addr::UNSPECIFIED)), - config.grpc_port, + env_config.grpc_port, ); if let Err(e) = server_to_run.run(addr).await { @@ -263,18 +252,18 @@ pub async fn run_server(config: Config, logs_rx: LogsReceiver) -> anyhow::Result key, grpc_server, remote_mfa_sessions: Arc::new(tokio::sync::Mutex::new(HashMap::new())), - url: config.url.clone(), + url: env_config.url.clone(), }; // Setup tower_governor rate-limiter debug!( "Configuring rate limiter, per_second: {}, burst: {}", - config.rate_limit_per_second, config.rate_limit_burst + env_config.rate_limit_per_second, env_config.rate_limit_burst ); let governor_conf = GovernorConfigBuilder::default() .key_extractor(SmartIpKeyExtractor) - .per_second(config.rate_limit_per_second) - .burst_size(config.rate_limit_burst) + .per_second(env_config.rate_limit_per_second) + .burst_size(env_config.rate_limit_burst) .finish(); let governor_conf = if let Some(conf) = governor_conf { @@ -293,7 +282,7 @@ pub async fn run_server(config: Config, logs_rx: LogsReceiver) -> anyhow::Result }); info!( "Configured rate limiter, per_second: {}, burst: {}", - config.rate_limit_per_second, config.rate_limit_burst + env_config.rate_limit_per_second, env_config.rate_limit_burst ); Some(conf) } else { @@ -351,10 +340,10 @@ pub async fn run_server(config: Config, logs_rx: LogsReceiver) -> anyhow::Result debug!("Spawning API web server"); tasks.spawn(async move { let addr = SocketAddr::new( - config + env_config .http_bind_address .unwrap_or(IpAddr::V4(Ipv4Addr::UNSPECIFIED)), - config.http_port, + env_config.http_port, ); let listener = TcpListener::bind(&addr).await?; info!("API web server is listening on {addr}"); diff --git a/src/lib.rs b/src/lib.rs index c87e0274..9059a7d8 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -9,7 +9,7 @@ pub mod assets; pub mod config; mod enterprise; mod error; -mod grpc; +pub mod grpc; mod handlers; pub mod http; pub mod logging; diff --git a/src/logging.rs b/src/logging.rs index 44c0c88c..fbfd2405 100644 --- a/src/logging.rs +++ b/src/logging.rs @@ -32,9 +32,9 @@ use crate::proto::LogEntry; pub fn init_tracing( own_version: Version, level: &LevelFilter, - logs_tx: Sender, + logs_tx: Option>, ) -> Result<(), DefguardVersionError> { - tracing_subscriber::registry() + let subscriber = tracing_subscriber::registry() .with( EnvFilter::try_from_env("DEFGUARD_PROXY_LOG_FILTER").unwrap_or_else(|_| { format!("{level},h2=warn,h2::codec=off,tower=warn,hyper=warn").into() @@ -45,9 +45,14 @@ pub fn init_tracing( fmt::layer() .event_format(HttpVersionFormatter::new(own_version)) .fmt_fields(VersionFilteredFields), - ) - .with(GrpcLogLayer::new(logs_tx)) - .init(); + ); + + if let Some(tx) = logs_tx { + let grpc_layer = GrpcLogLayer::new(tx); + subscriber.with(grpc_layer).init(); + } else { + subscriber.init(); + } info!("Tracing initialized"); Ok(()) diff --git a/src/main.rs b/src/main.rs index a7e06d84..fe511ac5 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,8 +1,14 @@ -use std::sync::Arc; +use std::{fs::read_to_string, sync::Arc}; -use defguard_proxy::{config::get_config, http::run_server, logging::init_tracing, VERSION}; +use defguard_proxy::{ + config::get_env_config, + grpc::Configuration, + http::{run_server, run_setup, GRPC_CERT_NAME, GRPC_KEY_NAME}, + logging::init_tracing, + VERSION, +}; use defguard_version::Version; -use tokio::sync::mpsc; +use tokio::sync::{mpsc, Mutex}; #[tokio::main] async fn main() -> anyhow::Result<()> { @@ -11,17 +17,50 @@ async fn main() -> anyhow::Result<()> { dotenvy::dotenv().ok(); } + let env_config = get_env_config()?; + let cert_dir = env_config.cert_dir.clone(); + let (grpc_cert, grpc_key) = ( + read_to_string(cert_dir.join(GRPC_CERT_NAME)).ok(), + read_to_string(cert_dir.join(GRPC_KEY_NAME)).ok(), + ); + + let needs_setup = grpc_cert.is_none() || grpc_key.is_none(); + // TODO: The channel size may need to be adjusted or some other approach should be used // to avoid dropping log messages. - let (logs_tx, logs_rx) = mpsc::channel(200); + let (logs_tx, logs_rx) = if needs_setup { + let (logs_tx, logs_rx) = mpsc::channel(200); + (Some(logs_tx), Some(logs_rx)) + } else { + (None, None) + }; - let config = get_config()?; - init_tracing(Version::parse(VERSION)?, &config.log_level, logs_tx)?; + init_tracing(Version::parse(VERSION)?, &env_config.log_level, logs_tx)?; // read config from env tracing::info!("Starting ... version v{}", VERSION); + let proxy_configuration = if needs_setup { + if let Some(logs_rx) = logs_rx { + tracing::info!("gRPC certificates not found, running setup process"); + let proxy_configuration = run_setup(&env_config, Arc::new(Mutex::new(logs_rx))).await?; + tracing::info!("Setup process completed successfully"); + proxy_configuration + } else { + anyhow::bail!( + "gRPC certificates not found and logs receiver not available for setup process" + ); + } + } else if let (Some(grpc_cert), Some(grpc_key)) = (grpc_cert, grpc_key) { + Configuration { + grpc_cert_pem: grpc_cert, + grpc_key_pem: grpc_key, + } + } else { + anyhow::bail!("Failed to load gRPC certificates"); + }; + // run API web server - run_server(config, Arc::new(tokio::sync::Mutex::new(logs_rx))).await?; + run_server(env_config, proxy_configuration).await?; Ok(()) } diff --git a/src/setup.rs b/src/setup.rs index 51189d3b..7acfd3fc 100644 --- a/src/setup.rs +++ b/src/setup.rs @@ -1,9 +1,6 @@ use std::{ net::SocketAddr, - sync::{ - atomic::{AtomicBool, Ordering}, - Arc, LazyLock, Mutex, - }, + sync::{Arc, LazyLock, Mutex}, }; use defguard_version::{ @@ -17,7 +14,7 @@ use tonic::{transport::Server, Request, Response, Status}; use crate::{ error::ApiError, grpc::Configuration, - proto::{proxy_setup_server, DerPayload, InitialSetupInfo, LogEntry}, + proto::{proxy_setup_server, CertificateInfo, DerPayload, LogEntry}, CommsChannel, LogsReceiver, MIN_CORE_VERSION, VERSION, }; @@ -29,18 +26,20 @@ static SETUP_CHANNEL: LazyLock>> = LazyLock:: ) }); +const AUTH_HEADER: &str = "authorization"; + pub(crate) struct ProxySetupServer { - setup_in_progress: Arc, key_pair: Arc>>, logs_rx: LogsReceiver, + current_session_token: Arc>>, } impl Clone for ProxySetupServer { fn clone(&self) -> Self { Self { - setup_in_progress: Arc::clone(&self.setup_in_progress), key_pair: Arc::clone(&self.key_pair), logs_rx: Arc::clone(&self.logs_rx), + current_session_token: Arc::clone(&self.current_session_token), } } } @@ -48,9 +47,9 @@ impl Clone for ProxySetupServer { impl ProxySetupServer { pub fn new(logs_rx: LogsReceiver) -> Self { Self { - setup_in_progress: Arc::new(AtomicBool::new(false)), key_pair: Arc::new(Mutex::new(None)), logs_rx, + current_session_token: Arc::new(Mutex::new(None)), } } @@ -63,11 +62,17 @@ impl ProxySetupServer { addr: SocketAddr, ) -> Result { info!("gRPC waiting for setup connection from Core on {addr}"); + debug!("Initializing gRPC server builder for setup process"); let server_builder = Server::builder(); let mut server_config = None; + debug!("Parsing proxy version: {}", VERSION); let own_version = Version::parse(VERSION)?; + debug!( + "Setting up version interceptor with minimum Core version: {}", + MIN_CORE_VERSION + ); server_builder .layer(tonic::service::InterceptorLayer::new( DefguardVersionInterceptor::new( @@ -80,6 +85,7 @@ impl ProxySetupServer { .layer(DefguardVersionLayer::new(own_version)) .add_service(proxy_setup_server::ProxySetupServer::new(self.clone())) .serve_with_shutdown(addr, async { + debug!("Setup server started, waiting for configuration from Core"); let config = SETUP_CHANNEL.1.lock().await.recv().await; if let Some(cfg) = config { debug!("Received the passed Proxy configuration"); @@ -95,6 +101,7 @@ impl ProxySetupServer { })?; debug!("gRPC setup server on {addr} has shutdown after completing setup"); + debug!("Validating received server configuration"); Ok(server_config.map_or_else( || { @@ -109,34 +116,150 @@ impl ProxySetupServer { }, )?) } + + fn is_setup_in_progress(&self) -> bool { + let in_progress = self + .current_session_token + .lock() + .expect("Failed to acquire lock on current session token during proxy setup") + .is_some(); + debug!("Setup in progress check: {}", in_progress); + in_progress + } + + fn clear_setup_session(&self) { + debug!("Terminating setup session"); + self.current_session_token + .lock() + .expect("Failed to acquire lock on current session token during proxy setup") + .take(); + debug!("Setup session terminated"); + } + + fn initialize_setup_session(&self, token: String) { + debug!("Establishing new setup session with Core"); + self.current_session_token + .lock() + .expect("Failed to acquire lock on current session token during proxy setup") + .replace(token); + debug!("Setup session established"); + } + + fn verify_session_token(&self, token: &str) -> bool { + debug!("Validating setup session authorization"); + let is_valid = (*self + .current_session_token + .lock() + .expect("Failed to acquire lock on current session token during proxy setup")) + .as_ref() + .is_some_and(|t| t == token); + debug!("Authorization validation result: {}", is_valid); + is_valid + } } #[tonic::async_trait] impl proxy_setup_server::ProxySetup for ProxySetupServer { - type ReadLogsStream = UnboundedReceiverStream>; + type StartStream = UnboundedReceiverStream>; - async fn start( - &self, - request: Request, - ) -> Result, Status> { - if self.setup_in_progress.load(Ordering::SeqCst) { + #[instrument(skip(self, request))] + async fn start(&self, request: Request<()>) -> Result, Status> { + debug!("Core initiated setup process, preparing to stream logs"); + if self.is_setup_in_progress() { error!("Setup already in progress, rejecting new setup request"); return Err(Status::resource_exhausted("Setup already in progress")); } - self.setup_in_progress.store(true, Ordering::SeqCst); + debug!("Authenticating setup session with Core"); + let token = request + .metadata() + .get(AUTH_HEADER) + .and_then(|v| v.to_str().ok()) + .and_then(|s| s.strip_prefix("Bearer ")) + .ok_or_else(|| Status::unauthenticated("Missing or invalid authorization token"))?; + + debug!("Setup session authenticated successfully"); + self.initialize_setup_session(token.to_string()); + + debug!("Preparing to forward Proxy logs to Core in real-time"); + let logs_rx = self.logs_rx.clone(); + + let (tx, rx) = mpsc::unbounded_channel(); + let self_clone = self.clone(); + debug!("Starting log streaming to Core"); + tokio::spawn(async move { + loop { + let maybe_log_entry = logs_rx.lock().await.try_recv(); + match maybe_log_entry { + Ok(log_entry) => { + if tx.send(Ok(log_entry)).is_err() { + debug!( + "Failed to send log entry to gRPC stream: receiver disconnected" + ); + break; + } + } + Err(tokio::sync::mpsc::error::TryRecvError::Empty) => { + if tx.is_closed() { + debug!("gRPC stream receiver disconnected"); + break; + } + tokio::task::yield_now().await; + } + Err(tokio::sync::mpsc::error::TryRecvError::Disconnected) => { + debug!("Logs receiver disconnected"); + break; + } + } + } + self_clone.clear_setup_session(); + }); + + debug!("Log stream established, Core will now receive real-time Proxy logs"); + Ok(Response::new(UnboundedReceiverStream::new(rx))) + } + + #[instrument(skip(self, request))] + async fn get_csr( + &self, + request: Request, + ) -> Result, Status> { + debug!("Core requested Certificate Signing Request (CSR) generation"); + let token = request + .metadata() + .get(AUTH_HEADER) + .and_then(|v| v.to_str().ok()) + .and_then(|s| s.strip_prefix("Bearer ")) + .ok_or_else(|| Status::unauthenticated("Missing or invalid authorization token"))?; + + debug!("Validating Core's authorization for this setup step"); + if !self.verify_session_token(token) { + error!("Invalid session token in get_csr request"); + return Err(Status::unauthenticated("Invalid session token")); + } + let setup_info = request.into_inner(); + debug!( + "Will generate certificate for hostname: {}", + setup_info.cert_hostname + ); + debug!("Generating key pair"); let key_pair = match defguard_certs::generate_key_pair() { Ok(kp) => kp, Err(err) => { error!("Failed to generate key pair: {err}"); - self.setup_in_progress.store(false, Ordering::SeqCst); + self.clear_setup_session(); return Err(Status::internal("Failed to generate key pair")); } }; + debug!("Key pair created"); let subject_alt_names = vec![setup_info.cert_hostname]; + debug!( + "Preparing Certificate Signing Request for hostname: {:?}", + subject_alt_names + ); let csr = match defguard_certs::Csr::new( &key_pair, @@ -150,39 +273,66 @@ impl proxy_setup_server::ProxySetup for ProxySetupServer { Ok(csr) => csr, Err(err) => { error!("Failed to generate CSR: {err}"); - self.setup_in_progress.store(false, Ordering::SeqCst); + self.clear_setup_session(); return Err(Status::internal(format!("Failed to generate CSR: {err}"))); } }; + debug!("Certificate Signing Request prepared"); self.key_pair .lock() .expect("Failed to acquire lock on key pair during proxy setup when trying to store generated key pair") .replace(key_pair); + debug!("Encoding Certificate Signing Request for transmission"); let csr_der = csr.to_der(); let csr_request = DerPayload { der_data: csr_der.to_vec(), }; + debug!( + "Sending Certificate Signing Request to Core for signing ({} bytes)", + csr_request.der_data.len() + ); Ok(Response::new(csr_request)) } + #[instrument(skip(self, request))] async fn send_cert(&self, request: Request) -> Result, Status> { + debug!("Core sending back signed certificate for installation"); + let token = request + .metadata() + .get(AUTH_HEADER) + .and_then(|v| v.to_str().ok()) + .and_then(|s| s.strip_prefix("Bearer ")) + .ok_or_else(|| Status::unauthenticated("Missing or invalid authorization token"))?; + + debug!("Validating Core's authorization to complete setup"); + if !self.verify_session_token(token) { + error!("Invalid session token in send_cert request"); + return Err(Status::unauthenticated("Invalid session token")); + } + let der_payload = request.into_inner(); let cert_der = der_payload.der_data; + debug!( + "Received signed certificate from Core ({} bytes)", + cert_der.len() + ); + debug!("Parsing received certificate DER data"); let grpc_cert_pem = match defguard_certs::der_to_pem(&cert_der, defguard_certs::PemLabel::Certificate) { Ok(pem) => pem, Err(err) => { error!("Failed to convert certificate DER to PEM: {err}"); - self.setup_in_progress.store(false, Ordering::SeqCst); + self.clear_setup_session(); return Err(Status::internal(format!( "Failed to convert certificate DER to PEM: {err}" ))); } }; + debug!("Certificate processed successfully"); let key_pair = { let key_pair = self @@ -194,7 +344,7 @@ impl proxy_setup_server::ProxySetup for ProxySetupServer { kp } else { error!("Key pair not found during Proxy setup. Key pair generation step might have failed."); - self.setup_in_progress.store(false, Ordering::SeqCst); + self.clear_setup_session(); return Err(Status::internal("Key pair not found during Proxy setup. Key pair generation step might have failed.")); } }; @@ -204,39 +354,22 @@ impl proxy_setup_server::ProxySetup for ProxySetupServer { grpc_cert_pem, }; + debug!("Passing configuration to gRPC server for finalization"); match SETUP_CHANNEL.0.lock().await.send(Some(configuration)).await { - Ok(()) => info!("Configuration sent to gRPC server"), + Ok(()) => info!("Proxy configuration passed to gRPC server successfully"), Err(err) => { error!("Failed to send configuration to gRPC server: {err}"); - self.setup_in_progress.store(false, Ordering::SeqCst); + self.clear_setup_session(); return Err(Status::internal( "Failed to send configuration to gRPC server", )); } } - self.setup_in_progress.store(false, Ordering::SeqCst); + debug!("Setup process completed successfully, cleaning up temporary session"); + self.clear_setup_session(); + debug!("Confirming successful setup to Core"); Ok(Response::new(())) } - - async fn read_logs( - &self, - _request: Request<()>, - ) -> Result, Status> { - let logs_rx = self.logs_rx.clone(); - - let (tx, rx) = mpsc::unbounded_channel(); - - tokio::spawn(async move { - while let Some(log_entry) = logs_rx.lock().await.recv().await { - if let Err(e) = tx.send(Ok(log_entry)) { - debug!("Failed to send log entry to gRPC stream: receiver disconnected ({e})",); - break; - } - } - }); - - Ok(Response::new(UnboundedReceiverStream::new(rx))) - } } From f5a8278524ea657a98b19acdbd535cf035326a43 Mon Sep 17 00:00:00 2001 From: Aleksander <170264518+t-aleksander@users.noreply.github.com> Date: Mon, 26 Jan 2026 13:22:37 +0100 Subject: [PATCH 3/5] update proto --- proto | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/proto b/proto index ec48aca9..41343581 160000 --- a/proto +++ b/proto @@ -1 +1 @@ -Subproject commit ec48aca9438e7cdcb4fcdb01ce6dcb5dac7f8dd3 +Subproject commit 4134358160e4f819515c9a6e5c014434cfb46d74 From 3e20ad301ea936d5a865d3f985bc48a058e72ffb Mon Sep 17 00:00:00 2001 From: Aleksander <170264518+t-aleksander@users.noreply.github.com> Date: Mon, 26 Jan 2026 13:54:36 +0100 Subject: [PATCH 4/5] fix audit --- web/package.json | 7 +- web/pnpm-lock.yaml | 763 +++++++++++++++++---------------------- web/src/routeTree.gen.ts | 12 +- 3 files changed, 342 insertions(+), 440 deletions(-) diff --git a/web/package.json b/web/package.json index 0fd7c6e4..1fdfd5e1 100644 --- a/web/package.json +++ b/web/package.json @@ -27,7 +27,7 @@ "change-case": "^5.4.4", "clsx": "^2.1.1", "dayjs": "^1.11.19", - "lodash-es": "^4.17.21", + "lodash-es": "^4.17.23", "motion": "^12.23.25", "qrcode.react": "^4.2.0", "qs": "^6.14.1", @@ -60,5 +60,10 @@ "typescript-eslint": "^8.48.1", "vite": "^7.2.7", "vite-plugin-image-optimizer": "^2.0.3" + }, + "pnpm": { + "overrides": { + "seroval": "^1.4.1" + } } } diff --git a/web/pnpm-lock.yaml b/web/pnpm-lock.yaml index 3cd53a91..f0c1d705 100644 --- a/web/pnpm-lock.yaml +++ b/web/pnpm-lock.yaml @@ -4,6 +4,9 @@ settings: autoInstallPeers: true excludeLinksFromLockfile: false +overrides: + seroval: ^1.4.1 + importers: .: @@ -19,7 +22,7 @@ importers: version: 2.6.0 '@tanstack/react-devtools': specifier: ^0.8.4 - version: 0.8.4(@types/react-dom@19.2.3(@types/react@19.2.7))(@types/react@19.2.7)(csstype@3.2.3)(react-dom@19.2.1(react@19.2.1))(react@19.2.1)(solid-js@1.9.10) + version: 0.8.6(@types/react-dom@19.2.3(@types/react@19.2.7))(@types/react@19.2.7)(csstype@3.2.3)(react-dom@19.2.1(react@19.2.1))(react@19.2.1)(solid-js@1.9.10) '@tanstack/react-form': specifier: ^1.27.1 version: 1.27.1(react-dom@19.2.1(react@19.2.1))(react@19.2.1) @@ -31,10 +34,10 @@ importers: version: 5.91.1(@tanstack/react-query@5.90.12(react@19.2.1))(react@19.2.1) '@tanstack/react-router': specifier: ^1.140.0 - version: 1.140.0(react-dom@19.2.1(react@19.2.1))(react@19.2.1) + version: 1.157.15(react-dom@19.2.1(react@19.2.1))(react@19.2.1) '@tanstack/react-router-devtools': specifier: ^1.140.0 - version: 1.140.0(@tanstack/react-router@1.140.0(react-dom@19.2.1(react@19.2.1))(react@19.2.1))(@tanstack/router-core@1.140.0)(csstype@3.2.3)(react-dom@19.2.1(react@19.2.1))(react@19.2.1)(solid-js@1.9.10) + version: 1.140.0(@tanstack/react-router@1.157.15(react-dom@19.2.1(react@19.2.1))(react@19.2.1))(@tanstack/router-core@1.157.15)(csstype@3.2.3)(react-dom@19.2.1(react@19.2.1))(react@19.2.1)(solid-js@1.9.10) '@uidotdev/usehooks': specifier: ^2.4.1 version: 2.4.1(react-dom@19.2.1(react@19.2.1))(react@19.2.1) @@ -51,8 +54,8 @@ importers: specifier: ^1.11.19 version: 1.11.19 lodash-es: - specifier: ^4.17.21 - version: 4.17.21 + specifier: ^4.17.23 + version: 4.17.23 motion: specifier: ^12.23.25 version: 12.23.25(react-dom@19.2.1(react@19.2.1))(react@19.2.1) @@ -89,7 +92,7 @@ importers: version: 0.3.12(vite@7.2.7(@types/node@24.10.1)(sass@1.94.2)(tsx@4.21.0)) '@tanstack/router-plugin': specifier: ^1.140.0 - version: 1.140.0(@tanstack/react-router@1.140.0(react-dom@19.2.1(react@19.2.1))(react@19.2.1))(vite@7.2.7(@types/node@24.10.1)(sass@1.94.2)(tsx@4.21.0)) + version: 1.157.15(@tanstack/react-router@1.157.15(react-dom@19.2.1(react@19.2.1))(react@19.2.1))(vite@7.2.7(@types/node@24.10.1)(sass@1.94.2)(tsx@4.21.0)) '@types/lodash-es': specifier: ^4.17.12 version: 4.17.12 @@ -154,66 +157,42 @@ packages: resolution: {integrity: sha512-cjQ7ZlQ0Mv3b47hABuTevyTuYN4i+loJKGeV9flcCgIK37cCXRh+L1bd3iBHlynerhQ7BhCkn2BPbQUL+rGqFg==} engines: {node: '>=6.9.0'} - '@babel/compat-data@7.28.5': - resolution: {integrity: sha512-6uFXyCayocRbqhZOB+6XcuZbkMNimwfVGFji8CTZnCzOHVGvDqzvitu1re2AU5LROliz7eQPhB8CpAMvnx9EjA==} - engines: {node: '>=6.9.0'} - - '@babel/core@7.28.5': - resolution: {integrity: sha512-e7jT4DxYvIDLk1ZHmU/m/mB19rex9sv0c2ftBtjSBv+kVM/902eh0fINUzD7UwLLNR+jU585GxUJ8/EBfAM5fw==} + '@babel/code-frame@7.28.6': + resolution: {integrity: sha512-JYgintcMjRiCvS8mMECzaEn+m3PfoQiyqukOMCCVQtoJGYJw8j/8LBJEiqkHLkfwCcs74E3pbAUFNg7d9VNJ+Q==} engines: {node: '>=6.9.0'} - '@babel/generator@7.28.5': - resolution: {integrity: sha512-3EwLFhZ38J4VyIP6WNtt2kUdW9dokXA9Cr4IVIFHuCpZ3H8/YFOl5JjZHisrn1fATPBmKKqXzDFvh9fUwHz6CQ==} + '@babel/compat-data@7.28.6': + resolution: {integrity: sha512-2lfu57JtzctfIrcGMz992hyLlByuzgIk58+hhGCxjKZ3rWI82NnVLjXcaTqkI2NvlcvOskZaiZ5kjUALo3Lpxg==} engines: {node: '>=6.9.0'} - '@babel/helper-annotate-as-pure@7.27.3': - resolution: {integrity: sha512-fXSwMQqitTGeHLBC08Eq5yXz2m37E4pJX1qAU1+2cNedz/ifv/bVXft90VeSav5nFO61EcNgwr0aJxbyPaWBPg==} + '@babel/core@7.28.6': + resolution: {integrity: sha512-H3mcG6ZDLTlYfaSNi0iOKkigqMFvkTKlGUYlD8GW7nNOYRrevuA46iTypPyv+06V3fEmvvazfntkBU34L0azAw==} engines: {node: '>=6.9.0'} - '@babel/helper-compilation-targets@7.27.2': - resolution: {integrity: sha512-2+1thGUUWWjLTYTHZWK1n8Yga0ijBz1XAhUXcKy81rd5g6yh7hGqMp45v7cadSbEHc9G3OTv45SyneRN3ps4DQ==} + '@babel/generator@7.28.6': + resolution: {integrity: sha512-lOoVRwADj8hjf7al89tvQ2a1lf53Z+7tiXMgpZJL3maQPDxh0DgLMN62B2MKUOFcoodBHLMbDM6WAbKgNy5Suw==} engines: {node: '>=6.9.0'} - '@babel/helper-create-class-features-plugin@7.28.5': - resolution: {integrity: sha512-q3WC4JfdODypvxArsJQROfupPBq9+lMwjKq7C33GhbFYJsufD0yd/ziwD+hJucLeWsnFPWZjsU2DNFqBPE7jwQ==} + '@babel/helper-compilation-targets@7.28.6': + resolution: {integrity: sha512-JYtls3hqi15fcx5GaSNL7SCTJ2MNmjrkHXg4FSpOA/grxK8KwyZ5bubHsCq8FXCkua6xhuaaBit+3b7+VZRfcA==} engines: {node: '>=6.9.0'} - peerDependencies: - '@babel/core': ^7.0.0 '@babel/helper-globals@7.28.0': resolution: {integrity: sha512-+W6cISkXFa1jXsDEdYA8HeevQT/FULhxzR99pxphltZcVaugps53THCeiWA8SguxxpSp3gKPiuYfSWopkLQ4hw==} engines: {node: '>=6.9.0'} - '@babel/helper-member-expression-to-functions@7.28.5': - resolution: {integrity: sha512-cwM7SBRZcPCLgl8a7cY0soT1SptSzAlMH39vwiRpOQkJlh53r5hdHwLSCZpQdVLT39sZt+CRpNwYG4Y2v77atg==} + '@babel/helper-module-imports@7.28.6': + resolution: {integrity: sha512-l5XkZK7r7wa9LucGw9LwZyyCUscb4x37JWTPz7swwFE/0FMQAGpiWUZn8u9DzkSBWEcK25jmvubfpw2dnAMdbw==} engines: {node: '>=6.9.0'} - '@babel/helper-module-imports@7.27.1': - resolution: {integrity: sha512-0gSFWUPNXNopqtIPQvlD5WgXYI5GY2kP2cCvoT8kczjbfcfuIljTbcWrulD1CIPIX2gt1wghbDy08yE1p+/r3w==} - engines: {node: '>=6.9.0'} - - '@babel/helper-module-transforms@7.28.3': - resolution: {integrity: sha512-gytXUbs8k2sXS9PnQptz5o0QnpLL51SwASIORY6XaBKF88nsOT0Zw9szLqlSGQDP/4TljBAD5y98p2U1fqkdsw==} + '@babel/helper-module-transforms@7.28.6': + resolution: {integrity: sha512-67oXFAYr2cDLDVGLXTEABjdBJZ6drElUSI7WKp70NrpyISso3plG9SAGEF6y7zbha/wOzUByWWTJvEDVNIUGcA==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0 - '@babel/helper-optimise-call-expression@7.27.1': - resolution: {integrity: sha512-URMGH08NzYFhubNSGJrpUEphGKQwMQYBySzat5cAByY1/YgIRkULnIy3tAMeszlL/so2HbeilYloUmSpd7GdVw==} - engines: {node: '>=6.9.0'} - - '@babel/helper-plugin-utils@7.27.1': - resolution: {integrity: sha512-1gn1Up5YXka3YYAHGKpbideQ5Yjf1tDa9qYcgysz+cNCXukyLl6DjPXhD3VRwSb8c0J9tA4b2+rHEZtc6R0tlw==} - engines: {node: '>=6.9.0'} - - '@babel/helper-replace-supers@7.27.1': - resolution: {integrity: sha512-7EHz6qDZc8RYS5ElPoShMheWvEgERonFCs7IAonWLLUTXW59DP14bCZt89/GKyreYn8g3S83m21FelHKbeDCKA==} - engines: {node: '>=6.9.0'} - peerDependencies: - '@babel/core': ^7.0.0 - - '@babel/helper-skip-transparent-expression-wrappers@7.27.1': - resolution: {integrity: sha512-Tub4ZKEXqbPjXgWLl2+3JpQAYBJ8+ikpQ2Ocj/q/r0LwE3UhENh7EUabyHjz2kCEsrRY83ew2DQdHluuiDQFzg==} + '@babel/helper-plugin-utils@7.28.6': + resolution: {integrity: sha512-S9gzZ/bz83GRysI7gAD4wPT/AI3uCnY+9xn+Mx/KPs2JwHJIz1W8PZkg2cqyt3RNOBM8ejcXhV6y8Og7ly/Dug==} engines: {node: '>=6.9.0'} '@babel/helper-string-parser@7.27.1': @@ -228,55 +207,37 @@ packages: resolution: {integrity: sha512-YvjJow9FxbhFFKDSuFnVCe2WxXk1zWc22fFePVNEaWJEu8IrZVlda6N0uHwzZrUM1il7NC9Mlp4MaJYbYd9JSg==} engines: {node: '>=6.9.0'} - '@babel/helpers@7.28.4': - resolution: {integrity: sha512-HFN59MmQXGHVyYadKLVumYsA9dBFun/ldYxipEjzA4196jpLZd8UjEEBLkbEkvfYreDqJhZxYAWFPtrfhNpj4w==} + '@babel/helpers@7.28.6': + resolution: {integrity: sha512-xOBvwq86HHdB7WUDTfKfT/Vuxh7gElQ+Sfti2Cy6yIWNW05P8iUslOVcZ4/sKbE+/jQaukQAdz/gf3724kYdqw==} engines: {node: '>=6.9.0'} - '@babel/parser@7.28.5': - resolution: {integrity: sha512-KKBU1VGYR7ORr3At5HAtUQ+TV3SzRCXmA/8OdDZiLDBIZxVyzXuztPjfLd3BV1PRAQGCMWWSHYhL0F8d5uHBDQ==} + '@babel/parser@7.28.6': + resolution: {integrity: sha512-TeR9zWR18BvbfPmGbLampPMW+uW1NZnJlRuuHso8i87QZNq2JRF9i6RgxRqtEq+wQGsS19NNTWr2duhnE49mfQ==} engines: {node: '>=6.0.0'} hasBin: true - '@babel/plugin-syntax-jsx@7.27.1': - resolution: {integrity: sha512-y8YTNIeKoyhGd9O0Jiyzyyqk8gdjnumGTQPsz0xOZOQ2RmkVJeZ1vmmfIvFEKqucBG6axJGBZDE/7iI5suUI/w==} + '@babel/plugin-syntax-jsx@7.28.6': + resolution: {integrity: sha512-wgEmr06G6sIpqr8YDwA2dSRTE3bJ+V0IfpzfSY3Lfgd7YWOaAdlykvJi13ZKBt8cZHfgH1IXN+CL656W3uUa4w==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 - '@babel/plugin-syntax-typescript@7.27.1': - resolution: {integrity: sha512-xfYCBMxveHrRMnAWl1ZlPXOZjzkN82THFvLhQhFXFt81Z5HnN+EtUkZhv/zcKpmT3fzmWZB0ywiBrbC3vogbwQ==} + '@babel/plugin-syntax-typescript@7.28.6': + resolution: {integrity: sha512-+nDNmQye7nlnuuHDboPbGm00Vqg3oO8niRRL27/4LYHUsHYh0zJ1xWOz0uRwNFmM1Avzk8wZbc6rdiYhomzv/A==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 - '@babel/plugin-transform-modules-commonjs@7.27.1': - resolution: {integrity: sha512-OJguuwlTYlN0gBZFRPqwOGNWssZjfIUdS7HMYtN8c1KmwpwHFBwTeFZrg9XZa+DFTitWOW5iTAG7tyCUPsCCyw==} + '@babel/template@7.28.6': + resolution: {integrity: sha512-YA6Ma2KsCdGb+WC6UpBVFJGXL58MDA6oyONbjyF/+5sBgxY/dwkhLogbMT2GXXyU84/IhRw/2D1Os1B/giz+BQ==} engines: {node: '>=6.9.0'} - peerDependencies: - '@babel/core': ^7.0.0-0 - '@babel/plugin-transform-typescript@7.28.5': - resolution: {integrity: sha512-x2Qa+v/CuEoX7Dr31iAfr0IhInrVOWZU/2vJMJ00FOR/2nM0BcBEclpaf9sWCDc+v5e9dMrhSH8/atq/kX7+bA==} + '@babel/traverse@7.28.6': + resolution: {integrity: sha512-fgWX62k02qtjqdSNTAGxmKYY/7FSL9WAS1o2Hu5+I5m9T0yxZzr4cnrfXQ/MX0rIifthCSs6FKTlzYbJcPtMNg==} engines: {node: '>=6.9.0'} - peerDependencies: - '@babel/core': ^7.0.0-0 - '@babel/preset-typescript@7.28.5': - resolution: {integrity: sha512-+bQy5WOI2V6LJZpPVxY+yp66XdZ2yifu0Mc1aP5CQKgjn4QM5IN2i5fAZ4xKop47pr8rpVhiAeu+nDQa12C8+g==} - engines: {node: '>=6.9.0'} - peerDependencies: - '@babel/core': ^7.0.0-0 - - '@babel/template@7.27.2': - resolution: {integrity: sha512-LPDZ85aEJyYSd18/DkjNh4/y1ntkE5KwUHWTiqgRxruuZL2F1yuHligVHLvcHY2vMHXttKFpJn6LwfI7cw7ODw==} - engines: {node: '>=6.9.0'} - - '@babel/traverse@7.28.5': - resolution: {integrity: sha512-TCCj4t55U90khlYkVV/0TfkJkAkUg3jZFA3Neb7unZT8CPok7iiRfaX0F+WnqWqt7OxhOn0uBKXCw4lbL8W0aQ==} - engines: {node: '>=6.9.0'} - - '@babel/types@7.28.5': - resolution: {integrity: sha512-qQ5m48eI/MFLQ5PxQj4PFaprjyCTLI37ElWMmNs0K8Lk3dVeOdNpB3ks8jc7yM5CDmVC73eMVk/trk3fgmrUpA==} + '@babel/types@7.28.6': + resolution: {integrity: sha512-0ZrskXVEHSWIqZM/sQZ4EV3jZJXRkio/WCxaqKZP1g//CEWEPSfeZFcms4XeKBCHU0ZKnIkdJeU/kF+eRp5lBg==} engines: {node: '>=6.9.0'} '@biomejs/biome@2.3.8': @@ -377,8 +338,8 @@ packages: cpu: [ppc64] os: [aix] - '@esbuild/aix-ppc64@0.27.1': - resolution: {integrity: sha512-HHB50pdsBX6k47S4u5g/CaLjqS3qwaOVE5ILsq64jyzgMhLuCuZ8rGzM9yhsAjfjkbgUPMzZEPa7DAp7yz6vuA==} + '@esbuild/aix-ppc64@0.27.2': + resolution: {integrity: sha512-GZMB+a0mOMZs4MpDbj8RJp4cw+w1WV5NYD6xzgvzUJ5Ek2jerwfO2eADyI6ExDSUED+1X8aMbegahsJi+8mgpw==} engines: {node: '>=18'} cpu: [ppc64] os: [aix] @@ -389,8 +350,8 @@ packages: cpu: [arm64] os: [android] - '@esbuild/android-arm64@0.27.1': - resolution: {integrity: sha512-45fuKmAJpxnQWixOGCrS+ro4Uvb4Re9+UTieUY2f8AEc+t7d4AaZ6eUJ3Hva7dtrxAAWHtlEFsXFMAgNnGU9uQ==} + '@esbuild/android-arm64@0.27.2': + resolution: {integrity: sha512-pvz8ZZ7ot/RBphf8fv60ljmaoydPU12VuXHImtAs0XhLLw+EXBi2BLe3OYSBslR4rryHvweW5gmkKFwTiFy6KA==} engines: {node: '>=18'} cpu: [arm64] os: [android] @@ -401,8 +362,8 @@ packages: cpu: [arm] os: [android] - '@esbuild/android-arm@0.27.1': - resolution: {integrity: sha512-kFqa6/UcaTbGm/NncN9kzVOODjhZW8e+FRdSeypWe6j33gzclHtwlANs26JrupOntlcWmB0u8+8HZo8s7thHvg==} + '@esbuild/android-arm@0.27.2': + resolution: {integrity: sha512-DVNI8jlPa7Ujbr1yjU2PfUSRtAUZPG9I1RwW4F4xFB1Imiu2on0ADiI/c3td+KmDtVKNbi+nffGDQMfcIMkwIA==} engines: {node: '>=18'} cpu: [arm] os: [android] @@ -413,8 +374,8 @@ packages: cpu: [x64] os: [android] - '@esbuild/android-x64@0.27.1': - resolution: {integrity: sha512-LBEpOz0BsgMEeHgenf5aqmn/lLNTFXVfoWMUox8CtWWYK9X4jmQzWjoGoNb8lmAYml/tQ/Ysvm8q7szu7BoxRQ==} + '@esbuild/android-x64@0.27.2': + resolution: {integrity: sha512-z8Ank4Byh4TJJOh4wpz8g2vDy75zFL0TlZlkUkEwYXuPSgX8yzep596n6mT7905kA9uHZsf/o2OJZubl2l3M7A==} engines: {node: '>=18'} cpu: [x64] os: [android] @@ -425,8 +386,8 @@ packages: cpu: [arm64] os: [darwin] - '@esbuild/darwin-arm64@0.27.1': - resolution: {integrity: sha512-veg7fL8eMSCVKL7IW4pxb54QERtedFDfY/ASrumK/SbFsXnRazxY4YykN/THYqFnFwJ0aVjiUrVG2PwcdAEqQQ==} + '@esbuild/darwin-arm64@0.27.2': + resolution: {integrity: sha512-davCD2Zc80nzDVRwXTcQP/28fiJbcOwvdolL0sOiOsbwBa72kegmVU0Wrh1MYrbuCL98Omp5dVhQFWRKR2ZAlg==} engines: {node: '>=18'} cpu: [arm64] os: [darwin] @@ -437,8 +398,8 @@ packages: cpu: [x64] os: [darwin] - '@esbuild/darwin-x64@0.27.1': - resolution: {integrity: sha512-+3ELd+nTzhfWb07Vol7EZ+5PTbJ/u74nC6iv4/lwIU99Ip5uuY6QoIf0Hn4m2HoV0qcnRivN3KSqc+FyCHjoVQ==} + '@esbuild/darwin-x64@0.27.2': + resolution: {integrity: sha512-ZxtijOmlQCBWGwbVmwOF/UCzuGIbUkqB1faQRf5akQmxRJ1ujusWsb3CVfk/9iZKr2L5SMU5wPBi1UWbvL+VQA==} engines: {node: '>=18'} cpu: [x64] os: [darwin] @@ -449,8 +410,8 @@ packages: cpu: [arm64] os: [freebsd] - '@esbuild/freebsd-arm64@0.27.1': - resolution: {integrity: sha512-/8Rfgns4XD9XOSXlzUDepG8PX+AVWHliYlUkFI3K3GB6tqbdjYqdhcb4BKRd7C0BhZSoaCxhv8kTcBrcZWP+xg==} + '@esbuild/freebsd-arm64@0.27.2': + resolution: {integrity: sha512-lS/9CN+rgqQ9czogxlMcBMGd+l8Q3Nj1MFQwBZJyoEKI50XGxwuzznYdwcav6lpOGv5BqaZXqvBSiB/kJ5op+g==} engines: {node: '>=18'} cpu: [arm64] os: [freebsd] @@ -461,8 +422,8 @@ packages: cpu: [x64] os: [freebsd] - '@esbuild/freebsd-x64@0.27.1': - resolution: {integrity: sha512-GITpD8dK9C+r+5yRT/UKVT36h/DQLOHdwGVwwoHidlnA168oD3uxA878XloXebK4Ul3gDBBIvEdL7go9gCUFzQ==} + '@esbuild/freebsd-x64@0.27.2': + resolution: {integrity: sha512-tAfqtNYb4YgPnJlEFu4c212HYjQWSO/w/h/lQaBK7RbwGIkBOuNKQI9tqWzx7Wtp7bTPaGC6MJvWI608P3wXYA==} engines: {node: '>=18'} cpu: [x64] os: [freebsd] @@ -473,8 +434,8 @@ packages: cpu: [arm64] os: [linux] - '@esbuild/linux-arm64@0.27.1': - resolution: {integrity: sha512-W9//kCrh/6in9rWIBdKaMtuTTzNj6jSeG/haWBADqLLa9P8O5YSRDzgD5y9QBok4AYlzS6ARHifAb75V6G670Q==} + '@esbuild/linux-arm64@0.27.2': + resolution: {integrity: sha512-hYxN8pr66NsCCiRFkHUAsxylNOcAQaxSSkHMMjcpx0si13t1LHFphxJZUiGwojB1a/Hd5OiPIqDdXONia6bhTw==} engines: {node: '>=18'} cpu: [arm64] os: [linux] @@ -485,8 +446,8 @@ packages: cpu: [arm] os: [linux] - '@esbuild/linux-arm@0.27.1': - resolution: {integrity: sha512-ieMID0JRZY/ZeCrsFQ3Y3NlHNCqIhTprJfDgSB3/lv5jJZ8FX3hqPyXWhe+gvS5ARMBJ242PM+VNz/ctNj//eA==} + '@esbuild/linux-arm@0.27.2': + resolution: {integrity: sha512-vWfq4GaIMP9AIe4yj1ZUW18RDhx6EPQKjwe7n8BbIecFtCQG4CfHGaHuh7fdfq+y3LIA2vGS/o9ZBGVxIDi9hw==} engines: {node: '>=18'} cpu: [arm] os: [linux] @@ -497,8 +458,8 @@ packages: cpu: [ia32] os: [linux] - '@esbuild/linux-ia32@0.27.1': - resolution: {integrity: sha512-VIUV4z8GD8rtSVMfAj1aXFahsi/+tcoXXNYmXgzISL+KB381vbSTNdeZHHHIYqFyXcoEhu9n5cT+05tRv13rlw==} + '@esbuild/linux-ia32@0.27.2': + resolution: {integrity: sha512-MJt5BRRSScPDwG2hLelYhAAKh9imjHK5+NE/tvnRLbIqUWa+0E9N4WNMjmp/kXXPHZGqPLxggwVhz7QP8CTR8w==} engines: {node: '>=18'} cpu: [ia32] os: [linux] @@ -509,8 +470,8 @@ packages: cpu: [loong64] os: [linux] - '@esbuild/linux-loong64@0.27.1': - resolution: {integrity: sha512-l4rfiiJRN7sTNI//ff65zJ9z8U+k6zcCg0LALU5iEWzY+a1mVZ8iWC1k5EsNKThZ7XCQ6YWtsZ8EWYm7r1UEsg==} + '@esbuild/linux-loong64@0.27.2': + resolution: {integrity: sha512-lugyF1atnAT463aO6KPshVCJK5NgRnU4yb3FUumyVz+cGvZbontBgzeGFO1nF+dPueHD367a2ZXe1NtUkAjOtg==} engines: {node: '>=18'} cpu: [loong64] os: [linux] @@ -521,8 +482,8 @@ packages: cpu: [mips64el] os: [linux] - '@esbuild/linux-mips64el@0.27.1': - resolution: {integrity: sha512-U0bEuAOLvO/DWFdygTHWY8C067FXz+UbzKgxYhXC0fDieFa0kDIra1FAhsAARRJbvEyso8aAqvPdNxzWuStBnA==} + '@esbuild/linux-mips64el@0.27.2': + resolution: {integrity: sha512-nlP2I6ArEBewvJ2gjrrkESEZkB5mIoaTswuqNFRv/WYd+ATtUpe9Y09RnJvgvdag7he0OWgEZWhviS1OTOKixw==} engines: {node: '>=18'} cpu: [mips64el] os: [linux] @@ -533,8 +494,8 @@ packages: cpu: [ppc64] os: [linux] - '@esbuild/linux-ppc64@0.27.1': - resolution: {integrity: sha512-NzdQ/Xwu6vPSf/GkdmRNsOfIeSGnh7muundsWItmBsVpMoNPVpM61qNzAVY3pZ1glzzAxLR40UyYM23eaDDbYQ==} + '@esbuild/linux-ppc64@0.27.2': + resolution: {integrity: sha512-C92gnpey7tUQONqg1n6dKVbx3vphKtTHJaNG2Ok9lGwbZil6DrfyecMsp9CrmXGQJmZ7iiVXvvZH6Ml5hL6XdQ==} engines: {node: '>=18'} cpu: [ppc64] os: [linux] @@ -545,8 +506,8 @@ packages: cpu: [riscv64] os: [linux] - '@esbuild/linux-riscv64@0.27.1': - resolution: {integrity: sha512-7zlw8p3IApcsN7mFw0O1Z1PyEk6PlKMu18roImfl3iQHTnr/yAfYv6s4hXPidbDoI2Q0pW+5xeoM4eTCC0UdrQ==} + '@esbuild/linux-riscv64@0.27.2': + resolution: {integrity: sha512-B5BOmojNtUyN8AXlK0QJyvjEZkWwy/FKvakkTDCziX95AowLZKR6aCDhG7LeF7uMCXEJqwa8Bejz5LTPYm8AvA==} engines: {node: '>=18'} cpu: [riscv64] os: [linux] @@ -557,8 +518,8 @@ packages: cpu: [s390x] os: [linux] - '@esbuild/linux-s390x@0.27.1': - resolution: {integrity: sha512-cGj5wli+G+nkVQdZo3+7FDKC25Uh4ZVwOAK6A06Hsvgr8WqBBuOy/1s+PUEd/6Je+vjfm6stX0kmib5b/O2Ykw==} + '@esbuild/linux-s390x@0.27.2': + resolution: {integrity: sha512-p4bm9+wsPwup5Z8f4EpfN63qNagQ47Ua2znaqGH6bqLlmJ4bx97Y9JdqxgGZ6Y8xVTixUnEkoKSHcpRlDnNr5w==} engines: {node: '>=18'} cpu: [s390x] os: [linux] @@ -569,8 +530,8 @@ packages: cpu: [x64] os: [linux] - '@esbuild/linux-x64@0.27.1': - resolution: {integrity: sha512-z3H/HYI9MM0HTv3hQZ81f+AKb+yEoCRlUby1F80vbQ5XdzEMyY/9iNlAmhqiBKw4MJXwfgsh7ERGEOhrM1niMA==} + '@esbuild/linux-x64@0.27.2': + resolution: {integrity: sha512-uwp2Tip5aPmH+NRUwTcfLb+W32WXjpFejTIOWZFw/v7/KnpCDKG66u4DLcurQpiYTiYwQ9B7KOeMJvLCu/OvbA==} engines: {node: '>=18'} cpu: [x64] os: [linux] @@ -581,8 +542,8 @@ packages: cpu: [arm64] os: [netbsd] - '@esbuild/netbsd-arm64@0.27.1': - resolution: {integrity: sha512-wzC24DxAvk8Em01YmVXyjl96Mr+ecTPyOuADAvjGg+fyBpGmxmcr2E5ttf7Im8D0sXZihpxzO1isus8MdjMCXQ==} + '@esbuild/netbsd-arm64@0.27.2': + resolution: {integrity: sha512-Kj6DiBlwXrPsCRDeRvGAUb/LNrBASrfqAIok+xB0LxK8CHqxZ037viF13ugfsIpePH93mX7xfJp97cyDuTZ3cw==} engines: {node: '>=18'} cpu: [arm64] os: [netbsd] @@ -593,8 +554,8 @@ packages: cpu: [x64] os: [netbsd] - '@esbuild/netbsd-x64@0.27.1': - resolution: {integrity: sha512-1YQ8ybGi2yIXswu6eNzJsrYIGFpnlzEWRl6iR5gMgmsrR0FcNoV1m9k9sc3PuP5rUBLshOZylc9nqSgymI+TYg==} + '@esbuild/netbsd-x64@0.27.2': + resolution: {integrity: sha512-HwGDZ0VLVBY3Y+Nw0JexZy9o/nUAWq9MlV7cahpaXKW6TOzfVno3y3/M8Ga8u8Yr7GldLOov27xiCnqRZf0tCA==} engines: {node: '>=18'} cpu: [x64] os: [netbsd] @@ -605,8 +566,8 @@ packages: cpu: [arm64] os: [openbsd] - '@esbuild/openbsd-arm64@0.27.1': - resolution: {integrity: sha512-5Z+DzLCrq5wmU7RDaMDe2DVXMRm2tTDvX2KU14JJVBN2CT/qov7XVix85QoJqHltpvAOZUAc3ndU56HSMWrv8g==} + '@esbuild/openbsd-arm64@0.27.2': + resolution: {integrity: sha512-DNIHH2BPQ5551A7oSHD0CKbwIA/Ox7+78/AWkbS5QoRzaqlev2uFayfSxq68EkonB+IKjiuxBFoV8ESJy8bOHA==} engines: {node: '>=18'} cpu: [arm64] os: [openbsd] @@ -617,8 +578,8 @@ packages: cpu: [x64] os: [openbsd] - '@esbuild/openbsd-x64@0.27.1': - resolution: {integrity: sha512-Q73ENzIdPF5jap4wqLtsfh8YbYSZ8Q0wnxplOlZUOyZy7B4ZKW8DXGWgTCZmF8VWD7Tciwv5F4NsRf6vYlZtqg==} + '@esbuild/openbsd-x64@0.27.2': + resolution: {integrity: sha512-/it7w9Nb7+0KFIzjalNJVR5bOzA9Vay+yIPLVHfIQYG/j+j9VTH84aNB8ExGKPU4AzfaEvN9/V4HV+F+vo8OEg==} engines: {node: '>=18'} cpu: [x64] os: [openbsd] @@ -629,8 +590,8 @@ packages: cpu: [arm64] os: [openharmony] - '@esbuild/openharmony-arm64@0.27.1': - resolution: {integrity: sha512-ajbHrGM/XiK+sXM0JzEbJAen+0E+JMQZ2l4RR4VFwvV9JEERx+oxtgkpoKv1SevhjavK2z2ReHk32pjzktWbGg==} + '@esbuild/openharmony-arm64@0.27.2': + resolution: {integrity: sha512-LRBbCmiU51IXfeXk59csuX/aSaToeG7w48nMwA6049Y4J4+VbWALAuXcs+qcD04rHDuSCSRKdmY63sruDS5qag==} engines: {node: '>=18'} cpu: [arm64] os: [openharmony] @@ -641,8 +602,8 @@ packages: cpu: [x64] os: [sunos] - '@esbuild/sunos-x64@0.27.1': - resolution: {integrity: sha512-IPUW+y4VIjuDVn+OMzHc5FV4GubIwPnsz6ubkvN8cuhEqH81NovB53IUlrlBkPMEPxvNnf79MGBoz8rZ2iW8HA==} + '@esbuild/sunos-x64@0.27.2': + resolution: {integrity: sha512-kMtx1yqJHTmqaqHPAzKCAkDaKsffmXkPHThSfRwZGyuqyIeBvf08KSsYXl+abf5HDAPMJIPnbBfXvP2ZC2TfHg==} engines: {node: '>=18'} cpu: [x64] os: [sunos] @@ -653,8 +614,8 @@ packages: cpu: [arm64] os: [win32] - '@esbuild/win32-arm64@0.27.1': - resolution: {integrity: sha512-RIVRWiljWA6CdVu8zkWcRmGP7iRRIIwvhDKem8UMBjPql2TXM5PkDVvvrzMtj1V+WFPB4K7zkIGM7VzRtFkjdg==} + '@esbuild/win32-arm64@0.27.2': + resolution: {integrity: sha512-Yaf78O/B3Kkh+nKABUF++bvJv5Ijoy9AN1ww904rOXZFLWVc5OLOfL56W+C8F9xn5JQZa3UX6m+IktJnIb1Jjg==} engines: {node: '>=18'} cpu: [arm64] os: [win32] @@ -665,8 +626,8 @@ packages: cpu: [ia32] os: [win32] - '@esbuild/win32-ia32@0.27.1': - resolution: {integrity: sha512-2BR5M8CPbptC1AK5JbJT1fWrHLvejwZidKx3UMSF0ecHMa+smhi16drIrCEggkgviBwLYd5nwrFLSl5Kho96RQ==} + '@esbuild/win32-ia32@0.27.2': + resolution: {integrity: sha512-Iuws0kxo4yusk7sw70Xa2E2imZU5HoixzxfGCdxwBdhiDgt9vX9VUCBhqcwY7/uh//78A1hMkkROMJq9l27oLQ==} engines: {node: '>=18'} cpu: [ia32] os: [win32] @@ -677,8 +638,8 @@ packages: cpu: [x64] os: [win32] - '@esbuild/win32-x64@0.27.1': - resolution: {integrity: sha512-d5X6RMYv6taIymSk8JBP+nxv8DQAMY6A51GPgusqLdK9wBz5wWIXy1KjTck6HnjE9hqJzJRdk+1p/t5soSbCtw==} + '@esbuild/win32-x64@0.27.2': + resolution: {integrity: sha512-sRdU18mcKf7F+YgheI/zGf5alZatMUTKj/jNS6l744f9u3WFu4v7twcUI9vu4mknF4Y9aDlblIie0IM+5xxaqQ==} engines: {node: '>=18'} cpu: [x64] os: [win32] @@ -689,6 +650,12 @@ packages: peerDependencies: eslint: ^6.0.0 || ^7.0.0 || >=8.0.0 + '@eslint-community/eslint-utils@4.9.1': + resolution: {integrity: sha512-phrYmNiYppR7znFEdqgfWHXR6NCkZEK7hwWDHZUjit/2/U0r6XvkDl0SYnoM51Hq7FhCGdLDT6zxCCOY1hexsQ==} + engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} + peerDependencies: + eslint: ^6.0.0 || ^7.0.0 || >=8.0.0 + '@eslint-community/regexpp@4.12.2': resolution: {integrity: sha512-EriSTlt5OC9/7SXkRSCAhfSxxoSUgBm33OH+IkwbdpgoqsSsUg7y3uh+IICI/Qg4BBWr3U2i39RpmycbxMq4ew==} engines: {node: ^12.0.0 || ^14.0.0 || >=16.0.0} @@ -1289,8 +1256,8 @@ packages: peerDependencies: vite: ^6.0.0 || ^7.0.0 - '@tanstack/devtools@0.9.1': - resolution: {integrity: sha512-fW/1ewT+g0LgJGraS/Irwle3uRgM1VDwfhi/NP3aGHhGyCDAWJI0+Id9FBzjChQ5BuEU5qD5fdegcFqTZShXHw==} + '@tanstack/devtools@0.10.0': + resolution: {integrity: sha512-UVN6wMntMMfMXk3Ozn7Ytr+SNhhzICqzOqVxmd4P2Kw+WzLkkEtmrBOZICII64eEIOPpRWgs9EG8uWVPQBt4IA==} engines: {node: '>=18'} peerDependencies: solid-js: '>=1.9.7' @@ -1298,8 +1265,8 @@ packages: '@tanstack/form-core@1.27.1': resolution: {integrity: sha512-hPM+0tUnZ2C2zb2TE1lar1JJ0S0cbnQHlUwFcCnVBpMV3rjtUzkoM766gUpWrlmTGCzNad0GbJ0aTxVsjT6J8g==} - '@tanstack/history@1.140.0': - resolution: {integrity: sha512-u+/dChlWlT3kYa/RmFP+E7xY5EnzvKEKcvKk+XrgWMpBWExQIh3RQX/eUqhqwCXJPNc4jfm1Coj8umnm/hDgyA==} + '@tanstack/history@1.154.14': + resolution: {integrity: sha512-xyIfof8eHBuub1CkBnbKNKQXeRZC4dClhmzePHVOEel4G7lk/dW+TQ16da7CFdeNLv6u6Owf5VoBQxoo6DFTSA==} engines: {node: '>=12'} '@tanstack/pacer@0.15.4': @@ -1312,8 +1279,8 @@ packages: '@tanstack/query-devtools@5.91.1': resolution: {integrity: sha512-l8bxjk6BMsCaVQH6NzQEE/bEgFy1hAs5qbgXl0xhzezlaQbPk6Mgz9BqEg2vTLPOHD8N4k+w/gdgCbEzecGyNg==} - '@tanstack/react-devtools@0.8.4': - resolution: {integrity: sha512-fq7GrpHIRdIBa5HmNN+CmC7CopY3tfKE4AXoszNSLk4yHKjC8iEjx7rh4r4RO5iUxHnmoCKX+NPXDgfsIKtaog==} + '@tanstack/react-devtools@0.8.6': + resolution: {integrity: sha512-NUvbOlldLDzeL2qMONfLs5Ahb1bmygqyKMqYlNRl/UwAVW+ugIUGgDlXOa+kGt+ksCHO6CUopwEE9973z5tITg==} engines: {node: '>=18'} peerDependencies: '@types/react': '>=16.8' @@ -1353,8 +1320,8 @@ packages: '@tanstack/router-core': optional: true - '@tanstack/react-router@1.140.0': - resolution: {integrity: sha512-Xe4K1bEtU5h0cAhaKYXDQA2cuITgEs1x6tOognJbcxamlAdzDAkhYBhRg8dKSVAyfGejAUNlUi4utnN0s6R+Yw==} + '@tanstack/react-router@1.157.15': + resolution: {integrity: sha512-dVHX3Ann1rxLkXCrB9ctNKveGOrkmlKMo5fDIaaPCqqkDN/aC1gZ9O93i0OQVPUNekpkdXijmpHkxw12WqMTRQ==} engines: {node: '>=12'} peerDependencies: react: '>=18.0.0 || >=19.0.0' @@ -1366,8 +1333,8 @@ packages: react: ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 react-dom: ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 - '@tanstack/router-core@1.140.0': - resolution: {integrity: sha512-/Te/mlAzi5FEpZ9NF9RhVw/n+cWYLiCHpvevNKo7JPA8ZYWF58wkalPtNWSocftX4P+OIBNerFAW9UbLgSbvSw==} + '@tanstack/router-core@1.157.15': + resolution: {integrity: sha512-KaYz6s+wYcg92kRQ7HXlTJLhBaBXOYiiqRBv5tsRbKRIqqhWNyeGz5+NfDwaYFHg5XLSDs3DvN0elMtxcj4dTg==} engines: {node: '>=12'} '@tanstack/router-devtools-core@1.140.0': @@ -1381,16 +1348,16 @@ packages: csstype: optional: true - '@tanstack/router-generator@1.140.0': - resolution: {integrity: sha512-YYq/DSn7EkBboCySf87RDH3mNq3AfN18v4qHmre73KOdxUJchTZ4LC1+8vbO/1K/Uus2ZFXUDy7QX5KziNx08g==} + '@tanstack/router-generator@1.157.15': + resolution: {integrity: sha512-zGac6tyRFz/X86fk9/CAmS6z8lyZf4p9lhAqLBCKVkFiFPmU4eAJp1ODvs81EtV0uJdRL1/rb+uvgHLGUsmQ0g==} engines: {node: '>=12'} - '@tanstack/router-plugin@1.140.0': - resolution: {integrity: sha512-hUOOYTPLFS3LvGoPoQNk3BY3ZvPlVIgxnJT3JMJMdstLMT2RUYha3ddsaamZd4ONUSWmt+7N5OXmiG0v4XmzMw==} + '@tanstack/router-plugin@1.157.15': + resolution: {integrity: sha512-EpRYRb35//sVJ8GPBhthqfPt9HNhx1xAaejiQ8i4vkG37et6qaSGAO+Woq91WjnpmxMYs4+sNJpGioPuVLBBqQ==} engines: {node: '>=12'} peerDependencies: '@rsbuild/core': '>=1.0.2' - '@tanstack/react-router': ^1.140.0 + '@tanstack/react-router': ^1.157.15 vite: '>=5.0.0 || >=6.0.0 || >=7.0.0' vite-plugin-solid: ^2.11.10 webpack: '>=5.92.0' @@ -1406,8 +1373,8 @@ packages: webpack: optional: true - '@tanstack/router-utils@1.140.0': - resolution: {integrity: sha512-gobraqMjkR5OO4nNbnwursGo08Idla6Yu30RspIA9IR1hv4WPJlxIyRWJcKjiQeXGyu5TuekLPUOHM46oood7w==} + '@tanstack/router-utils@1.154.7': + resolution: {integrity: sha512-61bGx32tMKuEpVRseu2sh1KQe8CfB7793Mch/kyQt0EP3tD7X0sXmimCl3truRiDGUtI0CaSoQV1NPjAII1RBA==} engines: {node: '>=12'} '@tanstack/store@0.7.7': @@ -1416,8 +1383,8 @@ packages: '@tanstack/store@0.8.0': resolution: {integrity: sha512-Om+BO0YfMZe//X2z0uLF2j+75nQga6TpTJgLJQBiq85aOyZNIhkCgleNcud2KQg4k4v9Y9l+Uhru3qWMPGTOzQ==} - '@tanstack/virtual-file-routes@1.140.0': - resolution: {integrity: sha512-LVmd19QkxV3x40oHkuTii9ey3l5XDV+X8locO2p5zfVDUC+N58H2gA7cDUtVc9qtImncnz3WxQkO/6kM3PMx2w==} + '@tanstack/virtual-file-routes@1.154.7': + resolution: {integrity: sha512-cHHDnewHozgjpI+MIVp9tcib6lYEQK5MyUr0ChHpHFGBl8Xei55rohFK0I0ve/GKoHeioaK42Smd8OixPp6CTg==} engines: {node: '>=12'} '@types/debug@4.1.12': @@ -1602,8 +1569,8 @@ packages: axios@1.13.2: resolution: {integrity: sha512-VPk9ebNqPcy5lRGuSlKx752IlDatOjT9paPlm8A7yOuW2Fbvp4X3JznJtT4f0GzGLLiWE9W8onz51SqLYwzGaA==} - babel-dead-code-elimination@1.0.10: - resolution: {integrity: sha512-DV5bdJZTzZ0zn0DC24v3jD7Mnidh6xhKa4GfKCbq3sfW8kaWhDdZjP3i81geA8T33tdYqWKw4D3fVv0CwEgKVA==} + babel-dead-code-elimination@1.0.12: + resolution: {integrity: sha512-GERT7L2TiYcYDtYk1IpD+ASAYXjKbLTDPhBtYj7X1NuRMDTMtAx9kyBenub1Ev41lo91OHCKdmP+egTDmfQ7Ig==} bail@2.0.2: resolution: {integrity: sha512-0xO6mYd7JB2YesxDKplafRpsiOzPt9V02ddPCLbY1xYGPOX24NTyN50qnUxgCPcSoYMhKpAuBTjQoRZCAkUDRw==} @@ -1614,8 +1581,8 @@ packages: balanced-match@2.0.0: resolution: {integrity: sha512-1ugUSr8BHXRnK23KfuYS+gVMC3LB8QGH9W1iGtDPsNWoQbgtXSExkBu2aDR4epiGWZOjZsj6lDl/N/AqqTC3UA==} - baseline-browser-mapping@2.9.5: - resolution: {integrity: sha512-D5vIoztZOq1XM54LUdttJVc96ggEsIfju2JBvht06pSzpckp3C7HReun67Bghzrtdsq9XdMGbSSB3v3GhMNmAA==} + baseline-browser-mapping@2.9.18: + resolution: {integrity: sha512-e23vBV1ZLfjb9apvfPk4rHVu2ry6RIr2Wfs+O324okSidrX7pTAnEJPCh/O5BtRlr7QtZI7ktOP3vsqr7Z5XoA==} hasBin: true binary-extensions@2.3.0: @@ -1652,8 +1619,8 @@ packages: resolution: {integrity: sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==} engines: {node: '>=6'} - caniuse-lite@1.0.30001759: - resolution: {integrity: sha512-Pzfx9fOKoKvevQf8oCXoyNRQ5QyxJj+3O0Rqx2V5oxT61KGx8+n6hV/IUyJeifUci2clnmmKVpvtiqRzgiWjSw==} + caniuse-lite@1.0.30001766: + resolution: {integrity: sha512-4C0lfJ0/YPjJQHagaE9x2Elb69CIqEPZeG0anQt9SIvIoOH4a4uaRl73IavyO+0qZh6MDLH//DrXThEYKHkmYA==} ccount@2.0.1: resolution: {integrity: sha512-eyrF0jiFpY+3drT6383f1qhkbGsLSifNAjA61IUjZjmLCWjItY6LB9ft9YhoDgwfmclB2zhu51Lc7+95b8NRAg==} @@ -1809,8 +1776,8 @@ packages: devlop@1.1.0: resolution: {integrity: sha512-RWmIqhcFf1lRYBvNmr7qTNuyCt/7/ns2jbpp1+PalgE/rDQcBT0fioSMUpJ93irlUhC5hrg4cYqe6U+0ImW0rA==} - diff@8.0.2: - resolution: {integrity: sha512-sSuxWU5j5SR9QQji/o2qMvqRNYRDOcBTgsJ/DeCf4iSN4gW+gNMXM7wFIP+fdXZxoNiAnHUTGjCr+TSWXdRDKg==} + diff@8.0.3: + resolution: {integrity: sha512-qejHi7bcSD4hQAZE0tNAawRK1ZtafHDmMTMkrrIGgSLl7hTnQHmKCeB45xAcbfTqK2zowkM3j3bHt/4b/ARbYQ==} engines: {node: '>=0.3.1'} dir-glob@3.0.1: @@ -1821,8 +1788,8 @@ packages: resolution: {integrity: sha512-KIN/nDJBQRcXw0MLVhZE9iQHmG68qAVIBg9CqmUYjmQIhgij9U5MFvrqkUL5FbtyyzZuOeOt0zdeRe4UY7ct+A==} engines: {node: '>= 0.4'} - electron-to-chromium@1.5.266: - resolution: {integrity: sha512-kgWEglXvkEfMH7rxP5OSZZwnaDWT7J9EoZCujhnpLbfi0bbNtRkgdX2E3gt0Uer11c61qCYktB3hwkAS325sJg==} + electron-to-chromium@1.5.278: + resolution: {integrity: sha512-dQ0tM1svDRQOwxnXxm+twlGTjr9Upvt8UFWAgmLsxEzFQxhbti4VwxmMjsDxVC51Zo84swW7FVCXEV+VAkhuPw==} emoji-regex@8.0.0: resolution: {integrity: sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==} @@ -1855,8 +1822,8 @@ packages: engines: {node: '>=18'} hasBin: true - esbuild@0.27.1: - resolution: {integrity: sha512-yY35KZckJJuVVPXpvjgxiCuVEJT67F6zDeVTv4rizyPrfGBUpZQsvmxnN+C371c2esD/hNMjj4tpBhuueLN7aA==} + esbuild@0.27.2: + resolution: {integrity: sha512-HyNQImnsOC7X9PMNaCIeAm4ISCQXs5a5YasTXVliKv4uuBo1dKrG0A+uQS8M5eXjVMnLg3WgXaKvprHlFJQffw==} engines: {node: '>=18'} hasBin: true @@ -1899,8 +1866,8 @@ packages: engines: {node: '>=4'} hasBin: true - esquery@1.6.0: - resolution: {integrity: sha512-ca9pw9fomFcKPvFLXhBKUK90ZvGibiGOvRJNbjljY7s7uq/5YO4BOzcYtJqExdx99rF6aAcnRxHmcUHcz6sQsg==} + esquery@1.7.0: + resolution: {integrity: sha512-Ap6G0WQwcU/LHsvLwON1fAQX9Zp0A2Y6Y/cJBl9r/JbW90Zyg4/zbG6zzKa2OTALELarYHmKu0GhpM5EO+7T0g==} engines: {node: '>=0.10'} esrecurse@4.3.0: @@ -2179,8 +2146,8 @@ packages: resolution: {integrity: sha512-VRSzKkbMm5jMDoKLbltAkFQ5Qr7VDiTFGXxYFXXowVj387GeGNOCsOH6Msy00SGZ3Fp84b1Naa1psqgcCIEP5Q==} engines: {node: '>=0.10.0'} - isbot@5.1.32: - resolution: {integrity: sha512-VNfjM73zz2IBZmdShMfAUg10prm6t7HFUQmNAEOAVS4YH92ZrZcvkMcGX6cIgBJAzWDzPent/EeAtYEHNPNPBQ==} + isbot@5.1.33: + resolution: {integrity: sha512-P4Hgb5NqswjkI0J1CM6XKXon/sxKY1SuowE7Qx2hrBhIwICFyXy54mfgB5eMHXsbe/eStzzpbIGNOvGmz+dlKg==} engines: {node: '>=18'} isexe@2.0.0: @@ -2252,8 +2219,8 @@ packages: resolution: {integrity: sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==} engines: {node: '>=10'} - lodash-es@4.17.21: - resolution: {integrity: sha512-mKnC+QJ9pWVzv+C4/U3rRsHapFfHvQFoFB92e52xeyGMcX6/OlIl78je1u8vePzYZSkkogMPJ2yjxxsb89cxyw==} + lodash-es@4.17.23: + resolution: {integrity: sha512-kVI48u3PZr38HdYz98UmfPnXl2DXrpdctLrFLCd3kOx1xUkOmpFPx7gCWWM5MPkL/fD8zb+Ph0QzjGFs4+hHWg==} lodash.merge@4.6.2: resolution: {integrity: sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==} @@ -2636,20 +2603,16 @@ packages: resolution: {integrity: sha512-16OL3NnUBw8JG1jBLUoZJsLnQq0n5Ua6aHalhJK4fMQkz1lqR7Osz1sA30trBtd9VUDc2NgkuRCn8+/pBwqZ+w==} engines: {node: '>=10'} peerDependencies: - seroval: ^1.0 + seroval: ^1.4.1 - seroval-plugins@1.4.0: - resolution: {integrity: sha512-zir1aWzoiax6pbBVjoYVd0O1QQXgIL3eVGBMsBsNmM8Ukq90yGaWlfx0AB9dTS8GPqrOrbXn79vmItCUP9U3BQ==} + seroval-plugins@1.5.0: + resolution: {integrity: sha512-EAHqADIQondwRZIdeW2I636zgsODzoBDwb3PT/+7TLDWyw1Dy/Xv7iGUIEXXav7usHDE9HVhOU61irI3EnyyHA==} engines: {node: '>=10'} peerDependencies: - seroval: ^1.0 - - seroval@1.3.2: - resolution: {integrity: sha512-RbcPH1n5cfwKrru7v7+zrZvjLurgHhGyso3HTyGtRivGWgYjbOmGuivCQaORNELjNONoK35nj28EoWul9sb1zQ==} - engines: {node: '>=10'} + seroval: ^1.4.1 - seroval@1.4.0: - resolution: {integrity: sha512-BdrNXdzlofomLTiRnwJTSEAaGKyHHZkbMXIywOh7zlzp4uZnXErEwl9XZ+N1hJSNpeTtNxWvVwN0wUzAIQ4Hpg==} + seroval@1.5.0: + resolution: {integrity: sha512-OE4cvmJ1uSPrKorFIH9/w/Qwuvi/IMcGbv5RKgcJ/zjA/IohDLU6SVaxFN9FwajbP7nsX0dQqMDes1whk3y+yw==} engines: {node: '>=10'} sharp@0.34.5: @@ -2876,8 +2839,8 @@ packages: resolution: {integrity: sha512-5uKD0nqiYVzlmCRs01Fhs2BdkEgBS3SAVP6ndrBsuK42iC2+JHyxM05Rm9G8+5mkmRtzMZGY8Ct5+mliZxU/Ww==} engines: {node: '>=18.12.0'} - update-browserslist-db@1.2.2: - resolution: {integrity: sha512-E85pfNzMQ9jpKkA7+TJAi4TJN+tBCuWh5rUcS/sv6cFi+1q9LYDwDI5dpUL0u/73EElyQ8d3TEaeW4sPedBqYA==} + update-browserslist-db@1.2.3: + resolution: {integrity: sha512-Js0m9cx+qOgDxo0eMiFGEueWztz+d4+M3rGlmKPT+T4IS/jP4ylw3Nwpu6cpTTP8R1MAC1kF4VbdLt3ARf209w==} hasBin: true peerDependencies: browserslist: '>= 4.21.0' @@ -2979,8 +2942,8 @@ packages: resolution: {integrity: sha512-+QU2zd6OTD8XWIJCbffaiQeH9U73qIqafo1x6V1snCWYGJf6cVE0cDR4D8xRzcEnfI21IFrUPzPGtcPf8AC+Rw==} engines: {node: ^14.17.0 || ^16.13.0 || >=18.0.0} - ws@8.18.3: - resolution: {integrity: sha512-PEIGCY5tSlUt50cqyMXfCzX+oOPqN0vuGqWzbcJ2xvnkzkq46oOpz7dQaTDBdfICb4N14+GARUDw2XV2N4tvzg==} + ws@8.19.0: + resolution: {integrity: sha512-blAT2mjOEIi0ZzruJfIhb3nps74PRWTCz1IjglWEEpQl5XS/UNama6u2/rjFkDDouqr4L67ry+1aGIALViWjDg==} engines: {node: '>=10.0.0'} peerDependencies: bufferutil: ^4.0.1 @@ -3038,19 +3001,25 @@ snapshots: js-tokens: 4.0.0 picocolors: 1.1.1 - '@babel/compat-data@7.28.5': {} + '@babel/code-frame@7.28.6': + dependencies: + '@babel/helper-validator-identifier': 7.28.5 + js-tokens: 4.0.0 + picocolors: 1.1.1 + + '@babel/compat-data@7.28.6': {} - '@babel/core@7.28.5': + '@babel/core@7.28.6': dependencies: - '@babel/code-frame': 7.27.1 - '@babel/generator': 7.28.5 - '@babel/helper-compilation-targets': 7.27.2 - '@babel/helper-module-transforms': 7.28.3(@babel/core@7.28.5) - '@babel/helpers': 7.28.4 - '@babel/parser': 7.28.5 - '@babel/template': 7.27.2 - '@babel/traverse': 7.28.5 - '@babel/types': 7.28.5 + '@babel/code-frame': 7.28.6 + '@babel/generator': 7.28.6 + '@babel/helper-compilation-targets': 7.28.6 + '@babel/helper-module-transforms': 7.28.6(@babel/core@7.28.6) + '@babel/helpers': 7.28.6 + '@babel/parser': 7.28.6 + '@babel/template': 7.28.6 + '@babel/traverse': 7.28.6 + '@babel/types': 7.28.6 '@jridgewell/remapping': 2.3.5 convert-source-map: 2.0.0 debug: 4.4.3 @@ -3060,85 +3029,41 @@ snapshots: transitivePeerDependencies: - supports-color - '@babel/generator@7.28.5': + '@babel/generator@7.28.6': dependencies: - '@babel/parser': 7.28.5 - '@babel/types': 7.28.5 + '@babel/parser': 7.28.6 + '@babel/types': 7.28.6 '@jridgewell/gen-mapping': 0.3.13 '@jridgewell/trace-mapping': 0.3.31 jsesc: 3.1.0 - '@babel/helper-annotate-as-pure@7.27.3': - dependencies: - '@babel/types': 7.28.5 - - '@babel/helper-compilation-targets@7.27.2': + '@babel/helper-compilation-targets@7.28.6': dependencies: - '@babel/compat-data': 7.28.5 + '@babel/compat-data': 7.28.6 '@babel/helper-validator-option': 7.27.1 browserslist: 4.28.1 lru-cache: 5.1.1 semver: 6.3.1 - '@babel/helper-create-class-features-plugin@7.28.5(@babel/core@7.28.5)': - dependencies: - '@babel/core': 7.28.5 - '@babel/helper-annotate-as-pure': 7.27.3 - '@babel/helper-member-expression-to-functions': 7.28.5 - '@babel/helper-optimise-call-expression': 7.27.1 - '@babel/helper-replace-supers': 7.27.1(@babel/core@7.28.5) - '@babel/helper-skip-transparent-expression-wrappers': 7.27.1 - '@babel/traverse': 7.28.5 - semver: 6.3.1 - transitivePeerDependencies: - - supports-color - '@babel/helper-globals@7.28.0': {} - '@babel/helper-member-expression-to-functions@7.28.5': + '@babel/helper-module-imports@7.28.6': dependencies: - '@babel/traverse': 7.28.5 - '@babel/types': 7.28.5 + '@babel/traverse': 7.28.6 + '@babel/types': 7.28.6 transitivePeerDependencies: - supports-color - '@babel/helper-module-imports@7.27.1': + '@babel/helper-module-transforms@7.28.6(@babel/core@7.28.6)': dependencies: - '@babel/traverse': 7.28.5 - '@babel/types': 7.28.5 - transitivePeerDependencies: - - supports-color - - '@babel/helper-module-transforms@7.28.3(@babel/core@7.28.5)': - dependencies: - '@babel/core': 7.28.5 - '@babel/helper-module-imports': 7.27.1 + '@babel/core': 7.28.6 + '@babel/helper-module-imports': 7.28.6 '@babel/helper-validator-identifier': 7.28.5 - '@babel/traverse': 7.28.5 + '@babel/traverse': 7.28.6 transitivePeerDependencies: - supports-color - '@babel/helper-optimise-call-expression@7.27.1': - dependencies: - '@babel/types': 7.28.5 - - '@babel/helper-plugin-utils@7.27.1': {} - - '@babel/helper-replace-supers@7.27.1(@babel/core@7.28.5)': - dependencies: - '@babel/core': 7.28.5 - '@babel/helper-member-expression-to-functions': 7.28.5 - '@babel/helper-optimise-call-expression': 7.27.1 - '@babel/traverse': 7.28.5 - transitivePeerDependencies: - - supports-color - - '@babel/helper-skip-transparent-expression-wrappers@7.27.1': - dependencies: - '@babel/traverse': 7.28.5 - '@babel/types': 7.28.5 - transitivePeerDependencies: - - supports-color + '@babel/helper-plugin-utils@7.28.6': {} '@babel/helper-string-parser@7.27.1': {} @@ -3146,74 +3071,44 @@ snapshots: '@babel/helper-validator-option@7.27.1': {} - '@babel/helpers@7.28.4': + '@babel/helpers@7.28.6': dependencies: - '@babel/template': 7.27.2 - '@babel/types': 7.28.5 + '@babel/template': 7.28.6 + '@babel/types': 7.28.6 - '@babel/parser@7.28.5': + '@babel/parser@7.28.6': dependencies: - '@babel/types': 7.28.5 + '@babel/types': 7.28.6 - '@babel/plugin-syntax-jsx@7.27.1(@babel/core@7.28.5)': + '@babel/plugin-syntax-jsx@7.28.6(@babel/core@7.28.6)': dependencies: - '@babel/core': 7.28.5 - '@babel/helper-plugin-utils': 7.27.1 + '@babel/core': 7.28.6 + '@babel/helper-plugin-utils': 7.28.6 - '@babel/plugin-syntax-typescript@7.27.1(@babel/core@7.28.5)': + '@babel/plugin-syntax-typescript@7.28.6(@babel/core@7.28.6)': dependencies: - '@babel/core': 7.28.5 - '@babel/helper-plugin-utils': 7.27.1 + '@babel/core': 7.28.6 + '@babel/helper-plugin-utils': 7.28.6 - '@babel/plugin-transform-modules-commonjs@7.27.1(@babel/core@7.28.5)': + '@babel/template@7.28.6': dependencies: - '@babel/core': 7.28.5 - '@babel/helper-module-transforms': 7.28.3(@babel/core@7.28.5) - '@babel/helper-plugin-utils': 7.27.1 - transitivePeerDependencies: - - supports-color - - '@babel/plugin-transform-typescript@7.28.5(@babel/core@7.28.5)': - dependencies: - '@babel/core': 7.28.5 - '@babel/helper-annotate-as-pure': 7.27.3 - '@babel/helper-create-class-features-plugin': 7.28.5(@babel/core@7.28.5) - '@babel/helper-plugin-utils': 7.27.1 - '@babel/helper-skip-transparent-expression-wrappers': 7.27.1 - '@babel/plugin-syntax-typescript': 7.27.1(@babel/core@7.28.5) - transitivePeerDependencies: - - supports-color - - '@babel/preset-typescript@7.28.5(@babel/core@7.28.5)': - dependencies: - '@babel/core': 7.28.5 - '@babel/helper-plugin-utils': 7.27.1 - '@babel/helper-validator-option': 7.27.1 - '@babel/plugin-syntax-jsx': 7.27.1(@babel/core@7.28.5) - '@babel/plugin-transform-modules-commonjs': 7.27.1(@babel/core@7.28.5) - '@babel/plugin-transform-typescript': 7.28.5(@babel/core@7.28.5) - transitivePeerDependencies: - - supports-color + '@babel/code-frame': 7.28.6 + '@babel/parser': 7.28.6 + '@babel/types': 7.28.6 - '@babel/template@7.27.2': + '@babel/traverse@7.28.6': dependencies: - '@babel/code-frame': 7.27.1 - '@babel/parser': 7.28.5 - '@babel/types': 7.28.5 - - '@babel/traverse@7.28.5': - dependencies: - '@babel/code-frame': 7.27.1 - '@babel/generator': 7.28.5 + '@babel/code-frame': 7.28.6 + '@babel/generator': 7.28.6 '@babel/helper-globals': 7.28.0 - '@babel/parser': 7.28.5 - '@babel/template': 7.27.2 - '@babel/types': 7.28.5 + '@babel/parser': 7.28.6 + '@babel/template': 7.28.6 + '@babel/types': 7.28.6 debug: 4.4.3 transitivePeerDependencies: - supports-color - '@babel/types@7.28.5': + '@babel/types@7.28.6': dependencies: '@babel/helper-string-parser': 7.27.1 '@babel/helper-validator-identifier': 7.28.5 @@ -3292,157 +3187,157 @@ snapshots: '@esbuild/aix-ppc64@0.25.12': optional: true - '@esbuild/aix-ppc64@0.27.1': + '@esbuild/aix-ppc64@0.27.2': optional: true '@esbuild/android-arm64@0.25.12': optional: true - '@esbuild/android-arm64@0.27.1': + '@esbuild/android-arm64@0.27.2': optional: true '@esbuild/android-arm@0.25.12': optional: true - '@esbuild/android-arm@0.27.1': + '@esbuild/android-arm@0.27.2': optional: true '@esbuild/android-x64@0.25.12': optional: true - '@esbuild/android-x64@0.27.1': + '@esbuild/android-x64@0.27.2': optional: true '@esbuild/darwin-arm64@0.25.12': optional: true - '@esbuild/darwin-arm64@0.27.1': + '@esbuild/darwin-arm64@0.27.2': optional: true '@esbuild/darwin-x64@0.25.12': optional: true - '@esbuild/darwin-x64@0.27.1': + '@esbuild/darwin-x64@0.27.2': optional: true '@esbuild/freebsd-arm64@0.25.12': optional: true - '@esbuild/freebsd-arm64@0.27.1': + '@esbuild/freebsd-arm64@0.27.2': optional: true '@esbuild/freebsd-x64@0.25.12': optional: true - '@esbuild/freebsd-x64@0.27.1': + '@esbuild/freebsd-x64@0.27.2': optional: true '@esbuild/linux-arm64@0.25.12': optional: true - '@esbuild/linux-arm64@0.27.1': + '@esbuild/linux-arm64@0.27.2': optional: true '@esbuild/linux-arm@0.25.12': optional: true - '@esbuild/linux-arm@0.27.1': + '@esbuild/linux-arm@0.27.2': optional: true '@esbuild/linux-ia32@0.25.12': optional: true - '@esbuild/linux-ia32@0.27.1': + '@esbuild/linux-ia32@0.27.2': optional: true '@esbuild/linux-loong64@0.25.12': optional: true - '@esbuild/linux-loong64@0.27.1': + '@esbuild/linux-loong64@0.27.2': optional: true '@esbuild/linux-mips64el@0.25.12': optional: true - '@esbuild/linux-mips64el@0.27.1': + '@esbuild/linux-mips64el@0.27.2': optional: true '@esbuild/linux-ppc64@0.25.12': optional: true - '@esbuild/linux-ppc64@0.27.1': + '@esbuild/linux-ppc64@0.27.2': optional: true '@esbuild/linux-riscv64@0.25.12': optional: true - '@esbuild/linux-riscv64@0.27.1': + '@esbuild/linux-riscv64@0.27.2': optional: true '@esbuild/linux-s390x@0.25.12': optional: true - '@esbuild/linux-s390x@0.27.1': + '@esbuild/linux-s390x@0.27.2': optional: true '@esbuild/linux-x64@0.25.12': optional: true - '@esbuild/linux-x64@0.27.1': + '@esbuild/linux-x64@0.27.2': optional: true '@esbuild/netbsd-arm64@0.25.12': optional: true - '@esbuild/netbsd-arm64@0.27.1': + '@esbuild/netbsd-arm64@0.27.2': optional: true '@esbuild/netbsd-x64@0.25.12': optional: true - '@esbuild/netbsd-x64@0.27.1': + '@esbuild/netbsd-x64@0.27.2': optional: true '@esbuild/openbsd-arm64@0.25.12': optional: true - '@esbuild/openbsd-arm64@0.27.1': + '@esbuild/openbsd-arm64@0.27.2': optional: true '@esbuild/openbsd-x64@0.25.12': optional: true - '@esbuild/openbsd-x64@0.27.1': + '@esbuild/openbsd-x64@0.27.2': optional: true '@esbuild/openharmony-arm64@0.25.12': optional: true - '@esbuild/openharmony-arm64@0.27.1': + '@esbuild/openharmony-arm64@0.27.2': optional: true '@esbuild/sunos-x64@0.25.12': optional: true - '@esbuild/sunos-x64@0.27.1': + '@esbuild/sunos-x64@0.27.2': optional: true '@esbuild/win32-arm64@0.25.12': optional: true - '@esbuild/win32-arm64@0.27.1': + '@esbuild/win32-arm64@0.27.2': optional: true '@esbuild/win32-ia32@0.25.12': optional: true - '@esbuild/win32-ia32@0.27.1': + '@esbuild/win32-ia32@0.27.2': optional: true '@esbuild/win32-x64@0.25.12': optional: true - '@esbuild/win32-x64@0.27.1': + '@esbuild/win32-x64@0.27.2': optional: true '@eslint-community/eslint-utils@4.9.0(eslint@9.38.0)': @@ -3450,6 +3345,11 @@ snapshots: eslint: 9.38.0 eslint-visitor-keys: 3.4.3 + '@eslint-community/eslint-utils@4.9.1(eslint@9.38.0)': + dependencies: + eslint: 9.38.0 + eslint-visitor-keys: 3.4.3 + '@eslint-community/regexpp@4.12.2': {} '@eslint/config-array@0.21.1': @@ -3931,7 +3831,7 @@ snapshots: '@tanstack/devtools-event-bus@0.3.3': dependencies: - ws: 8.18.3 + ws: 8.19.0 transitivePeerDependencies: - bufferutil - utf-8-validate @@ -3950,11 +3850,11 @@ snapshots: '@tanstack/devtools-vite@0.3.12(vite@7.2.7(@types/node@24.10.1)(sass@1.94.2)(tsx@4.21.0))': dependencies: - '@babel/core': 7.28.5 - '@babel/generator': 7.28.5 - '@babel/parser': 7.28.5 - '@babel/traverse': 7.28.5 - '@babel/types': 7.28.5 + '@babel/core': 7.28.6 + '@babel/generator': 7.28.6 + '@babel/parser': 7.28.6 + '@babel/traverse': 7.28.6 + '@babel/types': 7.28.6 '@tanstack/devtools-client': 0.0.5 '@tanstack/devtools-event-bus': 0.3.3 chalk: 5.6.2 @@ -3966,7 +3866,7 @@ snapshots: - supports-color - utf-8-validate - '@tanstack/devtools@0.9.1(csstype@3.2.3)(solid-js@1.9.10)': + '@tanstack/devtools@0.10.0(csstype@3.2.3)(solid-js@1.9.10)': dependencies: '@solid-primitives/event-listener': 2.4.3(solid-js@1.9.10) '@solid-primitives/keyboard': 1.3.3(solid-js@1.9.10) @@ -3988,7 +3888,7 @@ snapshots: '@tanstack/pacer': 0.15.4 '@tanstack/store': 0.7.7 - '@tanstack/history@1.140.0': {} + '@tanstack/history@1.154.14': {} '@tanstack/pacer@0.15.4': dependencies: @@ -3999,9 +3899,9 @@ snapshots: '@tanstack/query-devtools@5.91.1': {} - '@tanstack/react-devtools@0.8.4(@types/react-dom@19.2.3(@types/react@19.2.7))(@types/react@19.2.7)(csstype@3.2.3)(react-dom@19.2.1(react@19.2.1))(react@19.2.1)(solid-js@1.9.10)': + '@tanstack/react-devtools@0.8.6(@types/react-dom@19.2.3(@types/react@19.2.7))(@types/react@19.2.7)(csstype@3.2.3)(react-dom@19.2.1(react@19.2.1))(react@19.2.1)(solid-js@1.9.10)': dependencies: - '@tanstack/devtools': 0.9.1(csstype@3.2.3)(solid-js@1.9.10) + '@tanstack/devtools': 0.10.0(csstype@3.2.3)(solid-js@1.9.10) '@types/react': 19.2.7 '@types/react-dom': 19.2.3(@types/react@19.2.7) react: 19.2.1 @@ -4031,24 +3931,24 @@ snapshots: '@tanstack/query-core': 5.90.12 react: 19.2.1 - '@tanstack/react-router-devtools@1.140.0(@tanstack/react-router@1.140.0(react-dom@19.2.1(react@19.2.1))(react@19.2.1))(@tanstack/router-core@1.140.0)(csstype@3.2.3)(react-dom@19.2.1(react@19.2.1))(react@19.2.1)(solid-js@1.9.10)': + '@tanstack/react-router-devtools@1.140.0(@tanstack/react-router@1.157.15(react-dom@19.2.1(react@19.2.1))(react@19.2.1))(@tanstack/router-core@1.157.15)(csstype@3.2.3)(react-dom@19.2.1(react@19.2.1))(react@19.2.1)(solid-js@1.9.10)': dependencies: - '@tanstack/react-router': 1.140.0(react-dom@19.2.1(react@19.2.1))(react@19.2.1) - '@tanstack/router-devtools-core': 1.140.0(@tanstack/router-core@1.140.0)(csstype@3.2.3)(solid-js@1.9.10) + '@tanstack/react-router': 1.157.15(react-dom@19.2.1(react@19.2.1))(react@19.2.1) + '@tanstack/router-devtools-core': 1.140.0(@tanstack/router-core@1.157.15)(csstype@3.2.3)(solid-js@1.9.10) react: 19.2.1 react-dom: 19.2.1(react@19.2.1) optionalDependencies: - '@tanstack/router-core': 1.140.0 + '@tanstack/router-core': 1.157.15 transitivePeerDependencies: - csstype - solid-js - '@tanstack/react-router@1.140.0(react-dom@19.2.1(react@19.2.1))(react@19.2.1)': + '@tanstack/react-router@1.157.15(react-dom@19.2.1(react@19.2.1))(react@19.2.1)': dependencies: - '@tanstack/history': 1.140.0 + '@tanstack/history': 1.154.14 '@tanstack/react-store': 0.8.0(react-dom@19.2.1(react@19.2.1))(react@19.2.1) - '@tanstack/router-core': 1.140.0 - isbot: 5.1.32 + '@tanstack/router-core': 1.157.15 + isbot: 5.1.33 react: 19.2.1 react-dom: 19.2.1(react@19.2.1) tiny-invariant: 1.3.3 @@ -4061,19 +3961,19 @@ snapshots: react-dom: 19.2.1(react@19.2.1) use-sync-external-store: 1.6.0(react@19.2.1) - '@tanstack/router-core@1.140.0': + '@tanstack/router-core@1.157.15': dependencies: - '@tanstack/history': 1.140.0 + '@tanstack/history': 1.154.14 '@tanstack/store': 0.8.0 cookie-es: 2.0.0 - seroval: 1.4.0 - seroval-plugins: 1.4.0(seroval@1.4.0) + seroval: 1.5.0 + seroval-plugins: 1.5.0(seroval@1.5.0) tiny-invariant: 1.3.3 tiny-warning: 1.0.3 - '@tanstack/router-devtools-core@1.140.0(@tanstack/router-core@1.140.0)(csstype@3.2.3)(solid-js@1.9.10)': + '@tanstack/router-devtools-core@1.140.0(@tanstack/router-core@1.157.15)(csstype@3.2.3)(solid-js@1.9.10)': dependencies: - '@tanstack/router-core': 1.140.0 + '@tanstack/router-core': 1.157.15 clsx: 2.1.1 goober: 2.1.18(csstype@3.2.3) solid-js: 1.9.10 @@ -4081,11 +3981,11 @@ snapshots: optionalDependencies: csstype: 3.2.3 - '@tanstack/router-generator@1.140.0': + '@tanstack/router-generator@1.157.15': dependencies: - '@tanstack/router-core': 1.140.0 - '@tanstack/router-utils': 1.140.0 - '@tanstack/virtual-file-routes': 1.140.0 + '@tanstack/router-core': 1.157.15 + '@tanstack/router-utils': 1.154.7 + '@tanstack/virtual-file-routes': 1.154.7 prettier: 3.7.4 recast: 0.23.11 source-map: 0.7.6 @@ -4094,36 +3994,35 @@ snapshots: transitivePeerDependencies: - supports-color - '@tanstack/router-plugin@1.140.0(@tanstack/react-router@1.140.0(react-dom@19.2.1(react@19.2.1))(react@19.2.1))(vite@7.2.7(@types/node@24.10.1)(sass@1.94.2)(tsx@4.21.0))': - dependencies: - '@babel/core': 7.28.5 - '@babel/plugin-syntax-jsx': 7.27.1(@babel/core@7.28.5) - '@babel/plugin-syntax-typescript': 7.27.1(@babel/core@7.28.5) - '@babel/template': 7.27.2 - '@babel/traverse': 7.28.5 - '@babel/types': 7.28.5 - '@tanstack/router-core': 1.140.0 - '@tanstack/router-generator': 1.140.0 - '@tanstack/router-utils': 1.140.0 - '@tanstack/virtual-file-routes': 1.140.0 - babel-dead-code-elimination: 1.0.10 + '@tanstack/router-plugin@1.157.15(@tanstack/react-router@1.157.15(react-dom@19.2.1(react@19.2.1))(react@19.2.1))(vite@7.2.7(@types/node@24.10.1)(sass@1.94.2)(tsx@4.21.0))': + dependencies: + '@babel/core': 7.28.6 + '@babel/plugin-syntax-jsx': 7.28.6(@babel/core@7.28.6) + '@babel/plugin-syntax-typescript': 7.28.6(@babel/core@7.28.6) + '@babel/template': 7.28.6 + '@babel/traverse': 7.28.6 + '@babel/types': 7.28.6 + '@tanstack/router-core': 1.157.15 + '@tanstack/router-generator': 1.157.15 + '@tanstack/router-utils': 1.154.7 + '@tanstack/virtual-file-routes': 1.154.7 + babel-dead-code-elimination: 1.0.12 chokidar: 3.6.0 unplugin: 2.3.11 zod: 3.25.76 optionalDependencies: - '@tanstack/react-router': 1.140.0(react-dom@19.2.1(react@19.2.1))(react@19.2.1) + '@tanstack/react-router': 1.157.15(react-dom@19.2.1(react@19.2.1))(react@19.2.1) vite: 7.2.7(@types/node@24.10.1)(sass@1.94.2)(tsx@4.21.0) transitivePeerDependencies: - supports-color - '@tanstack/router-utils@1.140.0': + '@tanstack/router-utils@1.154.7': dependencies: - '@babel/core': 7.28.5 - '@babel/generator': 7.28.5 - '@babel/parser': 7.28.5 - '@babel/preset-typescript': 7.28.5(@babel/core@7.28.5) + '@babel/core': 7.28.6 + '@babel/generator': 7.28.6 + '@babel/parser': 7.28.6 ansis: 4.2.0 - diff: 8.0.2 + diff: 8.0.3 pathe: 2.0.3 tinyglobby: 0.2.15 transitivePeerDependencies: @@ -4133,7 +4032,7 @@ snapshots: '@tanstack/store@0.8.0': {} - '@tanstack/virtual-file-routes@1.140.0': {} + '@tanstack/virtual-file-routes@1.154.7': {} '@types/debug@4.1.12': dependencies: @@ -4345,12 +4244,12 @@ snapshots: transitivePeerDependencies: - debug - babel-dead-code-elimination@1.0.10: + babel-dead-code-elimination@1.0.12: dependencies: - '@babel/core': 7.28.5 - '@babel/parser': 7.28.5 - '@babel/traverse': 7.28.5 - '@babel/types': 7.28.5 + '@babel/core': 7.28.6 + '@babel/parser': 7.28.6 + '@babel/traverse': 7.28.6 + '@babel/types': 7.28.6 transitivePeerDependencies: - supports-color @@ -4360,7 +4259,7 @@ snapshots: balanced-match@2.0.0: {} - baseline-browser-mapping@2.9.5: {} + baseline-browser-mapping@2.9.18: {} binary-extensions@2.3.0: {} @@ -4379,11 +4278,11 @@ snapshots: browserslist@4.28.1: dependencies: - baseline-browser-mapping: 2.9.5 - caniuse-lite: 1.0.30001759 - electron-to-chromium: 1.5.266 + baseline-browser-mapping: 2.9.18 + caniuse-lite: 1.0.30001766 + electron-to-chromium: 1.5.278 node-releases: 2.0.27 - update-browserslist-db: 1.2.2(browserslist@4.28.1) + update-browserslist-db: 1.2.3(browserslist@4.28.1) cacheable@2.3.0: dependencies: @@ -4405,7 +4304,7 @@ snapshots: callsites@3.1.0: {} - caniuse-lite@1.0.30001759: {} + caniuse-lite@1.0.30001766: {} ccount@2.0.1: {} @@ -4529,7 +4428,7 @@ snapshots: dependencies: dequal: 2.0.3 - diff@8.0.2: {} + diff@8.0.3: {} dir-glob@3.0.1: dependencies: @@ -4541,7 +4440,7 @@ snapshots: es-errors: 1.3.0 gopd: 1.2.0 - electron-to-chromium@1.5.266: {} + electron-to-chromium@1.5.278: {} emoji-regex@8.0.0: {} @@ -4595,34 +4494,34 @@ snapshots: '@esbuild/win32-ia32': 0.25.12 '@esbuild/win32-x64': 0.25.12 - esbuild@0.27.1: + esbuild@0.27.2: optionalDependencies: - '@esbuild/aix-ppc64': 0.27.1 - '@esbuild/android-arm': 0.27.1 - '@esbuild/android-arm64': 0.27.1 - '@esbuild/android-x64': 0.27.1 - '@esbuild/darwin-arm64': 0.27.1 - '@esbuild/darwin-x64': 0.27.1 - '@esbuild/freebsd-arm64': 0.27.1 - '@esbuild/freebsd-x64': 0.27.1 - '@esbuild/linux-arm': 0.27.1 - '@esbuild/linux-arm64': 0.27.1 - '@esbuild/linux-ia32': 0.27.1 - '@esbuild/linux-loong64': 0.27.1 - '@esbuild/linux-mips64el': 0.27.1 - '@esbuild/linux-ppc64': 0.27.1 - '@esbuild/linux-riscv64': 0.27.1 - '@esbuild/linux-s390x': 0.27.1 - '@esbuild/linux-x64': 0.27.1 - '@esbuild/netbsd-arm64': 0.27.1 - '@esbuild/netbsd-x64': 0.27.1 - '@esbuild/openbsd-arm64': 0.27.1 - '@esbuild/openbsd-x64': 0.27.1 - '@esbuild/openharmony-arm64': 0.27.1 - '@esbuild/sunos-x64': 0.27.1 - '@esbuild/win32-arm64': 0.27.1 - '@esbuild/win32-ia32': 0.27.1 - '@esbuild/win32-x64': 0.27.1 + '@esbuild/aix-ppc64': 0.27.2 + '@esbuild/android-arm': 0.27.2 + '@esbuild/android-arm64': 0.27.2 + '@esbuild/android-x64': 0.27.2 + '@esbuild/darwin-arm64': 0.27.2 + '@esbuild/darwin-x64': 0.27.2 + '@esbuild/freebsd-arm64': 0.27.2 + '@esbuild/freebsd-x64': 0.27.2 + '@esbuild/linux-arm': 0.27.2 + '@esbuild/linux-arm64': 0.27.2 + '@esbuild/linux-ia32': 0.27.2 + '@esbuild/linux-loong64': 0.27.2 + '@esbuild/linux-mips64el': 0.27.2 + '@esbuild/linux-ppc64': 0.27.2 + '@esbuild/linux-riscv64': 0.27.2 + '@esbuild/linux-s390x': 0.27.2 + '@esbuild/linux-x64': 0.27.2 + '@esbuild/netbsd-arm64': 0.27.2 + '@esbuild/netbsd-x64': 0.27.2 + '@esbuild/openbsd-arm64': 0.27.2 + '@esbuild/openbsd-x64': 0.27.2 + '@esbuild/openharmony-arm64': 0.27.2 + '@esbuild/sunos-x64': 0.27.2 + '@esbuild/win32-arm64': 0.27.2 + '@esbuild/win32-ia32': 0.27.2 + '@esbuild/win32-x64': 0.27.2 escalade@3.2.0: {} @@ -4639,7 +4538,7 @@ snapshots: eslint@9.38.0: dependencies: - '@eslint-community/eslint-utils': 4.9.0(eslint@9.38.0) + '@eslint-community/eslint-utils': 4.9.1(eslint@9.38.0) '@eslint-community/regexpp': 4.12.2 '@eslint/config-array': 0.21.1 '@eslint/config-helpers': 0.4.2 @@ -4659,7 +4558,7 @@ snapshots: eslint-scope: 8.4.0 eslint-visitor-keys: 4.2.1 espree: 10.4.0 - esquery: 1.6.0 + esquery: 1.7.0 esutils: 2.0.3 fast-deep-equal: 3.1.3 file-entry-cache: 8.0.0 @@ -4684,7 +4583,7 @@ snapshots: esprima@4.0.1: {} - esquery@1.6.0: + esquery@1.7.0: dependencies: estraverse: 5.3.0 @@ -4941,7 +4840,7 @@ snapshots: is-plain-object@5.0.0: {} - isbot@5.1.32: {} + isbot@5.1.33: {} isexe@2.0.0: {} @@ -4997,7 +4896,7 @@ snapshots: dependencies: p-locate: 5.0.0 - lodash-es@4.17.21: {} + lodash-es@4.17.23: {} lodash.merge@4.6.2: {} @@ -5508,17 +5407,15 @@ snapshots: semver@7.7.3: {} - seroval-plugins@1.3.3(seroval@1.3.2): + seroval-plugins@1.3.3(seroval@1.5.0): dependencies: - seroval: 1.3.2 + seroval: 1.5.0 - seroval-plugins@1.4.0(seroval@1.4.0): + seroval-plugins@1.5.0(seroval@1.5.0): dependencies: - seroval: 1.4.0 - - seroval@1.3.2: {} + seroval: 1.5.0 - seroval@1.4.0: {} + seroval@1.5.0: {} sharp@0.34.5: dependencies: @@ -5600,8 +5497,8 @@ snapshots: solid-js@1.9.10: dependencies: csstype: 3.2.3 - seroval: 1.3.2 - seroval-plugins: 1.3.3(seroval@1.3.2) + seroval: 1.5.0 + seroval-plugins: 1.3.3(seroval@1.5.0) source-map-js@1.2.1: {} @@ -5770,7 +5667,7 @@ snapshots: tsx@4.21.0: dependencies: - esbuild: 0.27.1 + esbuild: 0.27.2 get-tsconfig: 4.13.0 optionalDependencies: fsevents: 2.3.3 @@ -5834,7 +5731,7 @@ snapshots: picomatch: 4.0.3 webpack-virtual-modules: 0.6.2 - update-browserslist-db@1.2.2(browserslist@4.28.1): + update-browserslist-db@1.2.3(browserslist@4.28.1): dependencies: browserslist: 4.28.1 escalade: 3.2.0 @@ -5903,7 +5800,7 @@ snapshots: imurmurhash: 0.1.4 signal-exit: 4.1.0 - ws@8.18.3: {} + ws@8.19.0: {} yallist@3.1.1: {} diff --git a/web/src/routeTree.gen.ts b/web/src/routeTree.gen.ts index cd512f5c..d89223d7 100644 --- a/web/src/routeTree.gen.ts +++ b/web/src/routeTree.gen.ts @@ -107,9 +107,9 @@ export interface FileRoutesByFullPath { '/openid/error': typeof OpenidErrorRoute '/password/finish': typeof PasswordFinishRoute '/password/sent': typeof PasswordSentRoute - '/password': typeof PasswordIndexRoute + '/password/': typeof PasswordIndexRoute '/openid/mfa/callback': typeof OpenidMfaCallbackRoute - '/openid/mfa': typeof OpenidMfaIndexRoute + '/openid/mfa/': typeof OpenidMfaIndexRoute } export interface FileRoutesByTo { '/': typeof IndexRoute @@ -158,9 +158,9 @@ export interface FileRouteTypes { | '/openid/error' | '/password/finish' | '/password/sent' - | '/password' + | '/password/' | '/openid/mfa/callback' - | '/openid/mfa' + | '/openid/mfa/' fileRoutesByTo: FileRoutesByTo to: | '/' @@ -266,7 +266,7 @@ declare module '@tanstack/react-router' { '/password/': { id: '/password/' path: '/password' - fullPath: '/password' + fullPath: '/password/' preLoaderRoute: typeof PasswordIndexRouteImport parentRoute: typeof rootRouteImport } @@ -301,7 +301,7 @@ declare module '@tanstack/react-router' { '/openid/mfa/': { id: '/openid/mfa/' path: '/openid/mfa' - fullPath: '/openid/mfa' + fullPath: '/openid/mfa/' preLoaderRoute: typeof OpenidMfaIndexRouteImport parentRoute: typeof rootRouteImport } From 5a5dd166a94797a670bcaef12ffbcaa0e2a8399c Mon Sep 17 00:00:00 2001 From: Aleksander <170264518+t-aleksander@users.noreply.github.com> Date: Mon, 26 Jan 2026 14:00:45 +0100 Subject: [PATCH 5/5] fix linter errors --- src/http.rs | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/src/http.rs b/src/http.rs index 1e796f5e..423ffe74 100644 --- a/src/http.rs +++ b/src/http.rs @@ -2,7 +2,7 @@ use std::{ collections::HashMap, net::{IpAddr, Ipv4Addr, SocketAddr}, path::Path, - sync::{atomic::Ordering, Arc, LazyLock, RwLock}, + sync::{atomic::Ordering, Arc, RwLock}, time::Duration, }; @@ -20,11 +20,7 @@ use axum_extra::extract::cookie::Key; use clap::crate_version; use defguard_version::{server::DefguardVersionLayer, Version}; use serde::Serialize; -use tokio::{ - net::TcpListener, - sync::{mpsc, oneshot, Mutex}, - task::JoinSet, -}; +use tokio::{net::TcpListener, sync::oneshot, task::JoinSet}; use tower_governor::{ governor::GovernorConfigBuilder, key_extractor::SmartIpKeyExtractor, GovernorLayer, };