From e57a37ebe4790c29b515c10648106316e9707624 Mon Sep 17 00:00:00 2001 From: cjus Date: Fri, 11 Oct 2024 08:00:45 -0600 Subject: [PATCH 01/19] log display --- Cargo.lock | 5 +- apps/framework-cli/Cargo.toml | 1 + apps/framework-cli/src/cli/routines.rs | 25 ++++ .../src/infrastructure/redis/redis_client.rs | 108 ++++++++++++++++-- 4 files changed, 130 insertions(+), 9 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index dab7167e7..f2c8094ed 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1993,6 +1993,7 @@ dependencies = [ "thiserror", "tokio", "tokio-cron-scheduler", + "tokio-stream", "toml", "toml_edit 0.22.16", "uuid", @@ -3767,9 +3768,9 @@ dependencies = [ [[package]] name = "tokio-stream" -version = "0.1.15" +version = "0.1.16" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "267ac89e0bec6e691e5813911606935d77c476ff49024f98abcea3e7b15e37af" +checksum = "4f4e6ce100d0eb49a2734f8c0812bcd324cf357d21810932c5df6b96ef2b86f1" dependencies = [ "futures-core", "pin-project-lite", diff --git a/apps/framework-cli/Cargo.toml b/apps/framework-cli/Cargo.toml index 42ccd3b3a..b25f9142f 100644 --- a/apps/framework-cli/Cargo.toml +++ b/apps/framework-cli/Cargo.toml @@ -77,6 +77,7 @@ sha2 = "0.10.8" hex = "0.4.2" constant_time_eq = "0.3.0" tokio-cron-scheduler = "0.11.0" +tokio-stream = "0.1.16" indexmap = "2.5.0" redis = { version = "0.24.0", features = ["tokio-comp", "aio", "tokio-native-tls-comp"] } jsonwebtoken = "9.3.0" diff --git a/apps/framework-cli/src/cli/routines.rs b/apps/framework-cli/src/cli/routines.rs index f1dc558a0..23435b7be 100644 --- a/apps/framework-cli/src/cli/routines.rs +++ b/apps/framework-cli/src/cli/routines.rs @@ -271,16 +271,41 @@ impl RoutineController { async fn setup_redis_client(project: Arc) -> anyhow::Result { let mut redis_client = RedisClient::new(project.name(), project.redis_config.clone()).await?; + show_message!( + MessageType::Info, + Message { + action: "Node Id:".to_string(), + details: format!( + "{}::{}", + redis_client.get_service_name(), + redis_client.get_instance_id() + ), + } + ); + // Register the leadership lock redis_client.register_lock("leadership", 10).await?; // Start the leadership lock management task start_leadership_lock_task(redis_client.clone(), project.clone()); + let callback = Arc::new(|message| { + tokio::spawn(async move { + process_pubsub_message(message).await; + }); + }); + + redis_client.register_message_handler(callback).await; + redis_client.start_periodic_tasks(); Ok(redis_client) } +async fn process_pubsub_message(message: String) { + info!("Received pubsub message: {}", message); + // TODO - process the message +} + fn start_leadership_lock_task(redis_client: RedisClient, project: Arc) { tokio::spawn(async move { let mut interval = interval(Duration::from_secs(5)); // Adjust the interval as needed diff --git a/apps/framework-cli/src/infrastructure/redis/redis_client.rs b/apps/framework-cli/src/infrastructure/redis/redis_client.rs index 4c9fe6d66..a38d603b0 100644 --- a/apps/framework-cli/src/infrastructure/redis/redis_client.rs +++ b/apps/framework-cli/src/infrastructure/redis/redis_client.rs @@ -46,9 +46,8 @@ //! Note: Make sure to set the MOOSE_REDIS_URL environment variable or the client will default to "redis://127.0.0.1:6379". use anyhow::{Context, Result}; use log::{error, info}; -use redis::aio::Connection as AsyncConnection; -use redis::AsyncCommands; -use redis::{Client, Script}; +use redis::aio::Connection as RedisConnection; +use redis::{AsyncCommands, Client, RedisError, Script}; use serde::{Deserialize, Serialize}; use std::collections::HashMap; use std::sync::Arc; @@ -56,12 +55,20 @@ use std::time::{SystemTime, UNIX_EPOCH}; use tokio::sync::Mutex; use tokio::task::JoinHandle; use tokio::time::{interval, Duration}; +use tokio_stream::StreamExt; use uuid::Uuid; // Internal constants that we don't expose to the user const KEY_EXPIRATION_TTL: u64 = 3; // 3 seconds const PRESENCE_UPDATE_INTERVAL: u64 = 1; // 1 second +// type alias for the callback function +use std::future::Future; +use std::pin::Pin; + +type MessageCallback = + Arc Pin + Send>> + Send + Sync>; + #[derive(Debug, Serialize, Deserialize, Clone)] pub struct RedisConfig { #[serde(default = "RedisConfig::default_url")] @@ -96,13 +103,15 @@ pub struct RedisLock { } pub struct RedisClient { - connection: Arc>, - pub_sub: Arc>, + connection: Arc>, + pub_sub: Arc>, redis_config: RedisConfig, service_name: String, instance_id: String, locks: HashMap, presence_task: Option>, + message_callbacks: Arc>>, + listener_task: Mutex>>, } impl RedisClient { @@ -136,7 +145,7 @@ impl RedisClient { Err(e) => error!("Redis connection failed: {}", e), } - Ok(Self { + let client = Self { connection: Arc::new(Mutex::new(connection)), pub_sub: Arc::new(Mutex::new(pub_sub)), redis_config, @@ -144,7 +153,23 @@ impl RedisClient { service_name, locks: HashMap::new(), presence_task: None, - }) + message_callbacks: Arc::new(Mutex::new(Vec::new())), + listener_task: Mutex::new(None), + }; + + // Start the message listener as part of initialization + match client.start_message_listener().await { + Ok(_) => info!("Successfully started message listener"), + Err(e) => error!("Failed to start message listener: {}", e), + } + + info!( + " Started {} with id {}", + client.get_service_name(), + client.get_instance_id() + ); + + Ok(client) } pub async fn presence_update(&mut self) -> Result<()> { @@ -399,6 +424,68 @@ impl RedisClient { .context("Failed to ping Redis server")?; Ok(()) } + + pub async fn register_message_handler(&self, callback: Arc) { + self.message_callbacks + .lock() + .await + .push(Arc::new(move |message: String| { + let callback = Arc::clone(&callback); + Box::pin(async move { + (callback)(message); + }) as Pin + Send>> + })); + } + + async fn start_message_listener(&self) -> Result<(), RedisError> { + let instance_channel = format!( + "{}::{}::{}::msgchannel", + self.redis_config.key_prefix, self.service_name, self.instance_id + ); + let broadcast_channel = format!( + "{}::{}::msgchannel", + self.redis_config.key_prefix, self.service_name + ); + + info!( + " Listening for messages on channels: {} and {}", + instance_channel, broadcast_channel + ); + + // Create a separate PubSub connection for listening to messages + let client = Client::open(self.redis_config.url.clone())?; + let pubsub_conn = client.get_async_connection().await?; + let mut pubsub = pubsub_conn.into_pubsub(); + + pubsub + .subscribe(&[&instance_channel, &broadcast_channel]) + .await + .map_err(|e| { + error!(" Failed to subscribe to channels: {}", e); + e + })?; + + let callback = self.message_callbacks.clone(); + + let listener_task = tokio::spawn(async move { + let mut pubsub_stream = pubsub.on_message(); + + while let Some(msg) = pubsub_stream.next().await { + if let Ok(payload) = msg.get_payload::() { + info!(" Received pubsub message: {}", payload); + let callbacks = callback.lock().await.clone(); + for cb in callbacks { + cb(payload.clone()).await; + } + } + } + }); + + // Store the listener task + *self.listener_task.lock().await = Some(listener_task); + + Ok(()) + } } impl Clone for RedisClient { @@ -411,6 +498,8 @@ impl Clone for RedisClient { service_name: self.service_name.clone(), locks: self.locks.clone(), presence_task: None, + message_callbacks: Arc::clone(&self.message_callbacks), + listener_task: Mutex::new(None), } } } @@ -434,6 +523,11 @@ impl Drop for RedisClient { } else { error!("Failed to get current runtime handle in RedisClient::drop"); } + if let Ok(mut guard) = self.listener_task.try_lock() { + if let Some(task) = guard.take() { + task.abort(); + } + } } } From 08544ce5344f3542de58bb2f2f9b6d223a707096 Mon Sep 17 00:00:00 2001 From: cjus Date: Fri, 11 Oct 2024 09:04:57 -0600 Subject: [PATCH 02/19] Add error logging --- .../src/infrastructure/redis/redis_client.rs | 23 ++++++++++++++++--- 1 file changed, 20 insertions(+), 3 deletions(-) diff --git a/apps/framework-cli/src/infrastructure/redis/redis_client.rs b/apps/framework-cli/src/infrastructure/redis/redis_client.rs index a38d603b0..b7f885354 100644 --- a/apps/framework-cli/src/infrastructure/redis/redis_client.rs +++ b/apps/framework-cli/src/infrastructure/redis/redis_client.rs @@ -164,7 +164,7 @@ impl RedisClient { } info!( - " Started {} with id {}", + " Started {}::{}", client.get_service_name(), client.get_instance_id() ); @@ -453,8 +453,25 @@ impl RedisClient { ); // Create a separate PubSub connection for listening to messages - let client = Client::open(self.redis_config.url.clone())?; - let pubsub_conn = client.get_async_connection().await?; + let client = match Client::open(self.redis_config.url.clone()) { + Ok(client) => client, + Err(e) => { + error!(" Failed to open Redis client: {}", e); + return Err(e); + } + }; + + let pubsub_conn = match client.get_async_connection().await { + Ok(conn) => conn, + Err(e) => { + error!( + " Failed to get async connection for PubSub: {}", + e + ); + return Err(e); + } + }; + let mut pubsub = pubsub_conn.into_pubsub(); pubsub From eeb033fb0fe1c538db26b130c18db26a676f43e7 Mon Sep 17 00:00:00 2001 From: cjus Date: Fri, 11 Oct 2024 10:28:14 -0600 Subject: [PATCH 03/19] Ensure message loop stays alive --- apps/framework-cli/src/cli/routines.rs | 12 +++++++--- .../src/infrastructure/redis/redis_client.rs | 23 +++++++++++-------- 2 files changed, 23 insertions(+), 12 deletions(-) diff --git a/apps/framework-cli/src/cli/routines.rs b/apps/framework-cli/src/cli/routines.rs index 23435b7be..788555667 100644 --- a/apps/framework-cli/src/cli/routines.rs +++ b/apps/framework-cli/src/cli/routines.rs @@ -302,8 +302,13 @@ async fn setup_redis_client(project: Arc) -> anyhow::ResultReceived pubsub message: {}", message); - // TODO - process the message + if message.contains("") { + println!(" Migration start message received: {}", message); + } else if message.contains("") { + println!(" Migration end message received: {}", message); + } else { + println!(" Received pubsub message: {}", message); + } } fn start_leadership_lock_task(redis_client: RedisClient, project: Arc) { @@ -338,7 +343,8 @@ async fn manage_leadership_lock( } }); } else { - debug!("Failed to obtain leadership lock"); + // Don't log this as it's normal for the lock to not be available to non-laader instances + // debug!("Failed to obtain leadership lock"); } } } diff --git a/apps/framework-cli/src/infrastructure/redis/redis_client.rs b/apps/framework-cli/src/infrastructure/redis/redis_client.rs index b7f885354..cc9069c75 100644 --- a/apps/framework-cli/src/infrastructure/redis/redis_client.rs +++ b/apps/framework-cli/src/infrastructure/redis/redis_client.rs @@ -45,7 +45,7 @@ //! //! Note: Make sure to set the MOOSE_REDIS_URL environment variable or the client will default to "redis://127.0.0.1:6379". use anyhow::{Context, Result}; -use log::{error, info}; +use log::{error, info, warn}; use redis::aio::Connection as RedisConnection; use redis::{AsyncCommands, Client, RedisError, Script}; use serde::{Deserialize, Serialize}; @@ -485,16 +485,21 @@ impl RedisClient { let callback = self.message_callbacks.clone(); let listener_task = tokio::spawn(async move { - let mut pubsub_stream = pubsub.on_message(); - - while let Some(msg) = pubsub_stream.next().await { - if let Ok(payload) = msg.get_payload::() { - info!(" Received pubsub message: {}", payload); - let callbacks = callback.lock().await.clone(); - for cb in callbacks { - cb(payload.clone()).await; + loop { + let mut pubsub_stream = pubsub.on_message(); + + while let Some(msg) = pubsub_stream.next().await { + if let Ok(payload) = msg.get_payload::() { + info!(" Received pubsub message: {}", payload); + let callbacks = callback.lock().await.clone(); + for cb in callbacks { + cb(payload.clone()).await; + } + } else { + warn!(" Failed to get payload from message"); } } + tokio::time::sleep(tokio::time::Duration::from_secs(1)).await; } }); From ff9d7af30118c0db13915c388c2a8001112db733 Mon Sep 17 00:00:00 2001 From: cjus Date: Mon, 14 Oct 2024 15:08:34 -0600 Subject: [PATCH 04/19] refactor for checking leadership flag --- apps/framework-cli/src/cli/routines.rs | 136 +++++++++++++++++-------- 1 file changed, 91 insertions(+), 45 deletions(-) diff --git a/apps/framework-cli/src/cli/routines.rs b/apps/framework-cli/src/cli/routines.rs index 788555667..b181c5a68 100644 --- a/apps/framework-cli/src/cli/routines.rs +++ b/apps/framework-cli/src/cli/routines.rs @@ -79,13 +79,14 @@ //! - Organize routines better in the file hiearchy //! +use crate::infrastructure::redis::redis_client::RedisClient; use std::collections::{HashMap, HashSet}; use std::ops::DerefMut; use std::path::PathBuf; use std::sync::Arc; use log::{debug, error, info}; -use tokio::sync::RwLock; // or use the appropriate error type +use tokio::sync::{Mutex, RwLock}; use tokio::time::{interval, Duration}; use crate::cli::watcher::{ @@ -112,7 +113,6 @@ use crate::infrastructure::processes::cron_registry::CronRegistry; use crate::infrastructure::processes::functions_registry::FunctionProcessRegistry; use crate::infrastructure::processes::kafka_clickhouse_sync::SyncingProcessesRegistry; use crate::infrastructure::processes::process_registry::ProcessRegistries; -use crate::infrastructure::redis::redis_client::RedisClient; use crate::infrastructure::stream::redpanda::fetch_topics; use crate::project::Project; @@ -123,6 +123,11 @@ use super::settings::Features; use super::watcher::FileWatcher; use super::{Message, MessageType}; +use std::sync::LazyLock; + +static REDIS_CLIENT: LazyLock>>>> = + LazyLock::new(|| Mutex::new(None)); + pub mod auth; pub mod block; pub mod clean; @@ -268,23 +273,32 @@ impl RoutineController { } } -async fn setup_redis_client(project: Arc) -> anyhow::Result { - let mut redis_client = RedisClient::new(project.name(), project.redis_config.clone()).await?; +async fn setup_redis_client(project: Arc) -> anyhow::Result>> { + let redis_client = RedisClient::new(project.name(), project.redis_config.clone()).await?; + let redis_client = Arc::new(Mutex::new(redis_client)); + + let (service_name, instance_id) = { + let client = redis_client.lock().await; + ( + client.get_service_name().to_string(), + client.get_instance_id().to_string(), + ) + }; show_message!( MessageType::Info, Message { action: "Node Id:".to_string(), - details: format!( - "{}::{}", - redis_client.get_service_name(), - redis_client.get_instance_id() - ), + details: format!("{}::{}", service_name, instance_id), } ); // Register the leadership lock - redis_client.register_lock("leadership", 10).await?; + redis_client + .lock() + .await + .register_lock("leadership", 10) + .await?; // Start the leadership lock management task start_leadership_lock_task(redis_client.clone(), project.clone()); @@ -295,23 +309,44 @@ async fn setup_redis_client(project: Arc) -> anyhow::Result") { - println!(" Migration start message received: {}", message); - } else if message.contains("") { - println!(" Migration end message received: {}", message); - } else { - println!(" Received pubsub message: {}", message); + let redis_client = { + let lock = REDIS_CLIENT.lock().await; + lock.clone().expect("Redis client not initialized") + }; + + if redis_client + .lock() + .await + .has_lock("leadership") + .await + .unwrap_or(false) + { + if message.contains("") { + println!(" Migration start message received: {}", message); + } else if message.contains("") { + println!(" Migration end message received: {}", message); + } else { + println!(" Received pubsub message: {}", message); + } } } -fn start_leadership_lock_task(redis_client: RedisClient, project: Arc) { +fn start_leadership_lock_task(redis_client: Arc>, project: Arc) { tokio::spawn(async move { let mut interval = interval(Duration::from_secs(5)); // Adjust the interval as needed loop { @@ -324,28 +359,33 @@ fn start_leadership_lock_task(redis_client: RedisClient, project: Arc) } async fn manage_leadership_lock( - redis_client: &RedisClient, + redis_client: &Arc>, project: &Arc, ) -> Result<(), anyhow::Error> { - match redis_client.has_lock("leadership").await? { - true => { - // We have the lock, renew it - redis_client.renew_lock("leadership").await?; - } - false => { - // We don't have the lock, try to acquire it - if redis_client.attempt_lock("leadership").await? { - info!("Obtained leadership lock, performing leadership tasks"); - let project_clone = project.clone(); - tokio::spawn(async move { - if let Err(e) = leadership_tasks(project_clone).await { - error!("Error executing leadership tasks: {}", e); - } - }); - } else { - // Don't log this as it's normal for the lock to not be available to non-laader instances - // debug!("Failed to obtain leadership lock"); - } + let has_lock = { + let client = redis_client.lock().await; + client.has_lock("leadership").await? + }; + + if has_lock { + // We have the lock, renew it + let client = redis_client.lock().await; + client.renew_lock("leadership").await?; + } else { + // We don't have the lock, try to acquire it + let acquired_lock = { + let client = redis_client.lock().await; + client.attempt_lock("leadership").await? + }; + + if acquired_lock { + info!("Obtained leadership lock, performing leadership tasks"); + let project_clone = project.clone(); + tokio::spawn(async move { + if let Err(e) = leadership_tasks(project_clone).await { + error!("Error executing leadership tasks: {}", e); + } + }); } } Ok(()) @@ -372,7 +412,7 @@ pub async fn start_development_mode( } ); - let mut redis_client = setup_redis_client(project.clone()).await?; + let redis_client = setup_redis_client(project.clone()).await?; let server_config = project.http_server_config.clone(); let web_server = Webserver::new( @@ -406,7 +446,7 @@ pub async fn start_development_mode( api_changes_channel, metrics.clone(), &mut client, - &redis_client, + &*redis_client.lock().await, // Dereference the MutexGuard ) .await?; // TODO - need to add a lock on the table to prevent concurrent updates as migrations are going through. @@ -561,7 +601,10 @@ pub async fn start_development_mode( .await; }; - let _ = redis_client.stop_periodic_tasks(); + { + let mut redis_client = redis_client.lock().await; + let _ = redis_client.stop_periodic_tasks(); + } Ok(()) } @@ -580,7 +623,7 @@ pub async fn start_production_mode( } ); - let mut redis_client = setup_redis_client(project.clone()).await?; + let redis_client = setup_redis_client(project.clone()).await?; let server_config = project.http_server_config.clone(); let web_server = Webserver::new( @@ -612,7 +655,7 @@ pub async fn start_production_mode( api_changes_channel, metrics.clone(), &mut client, - &redis_client, + &*redis_client.lock().await, // Dereference the MutexGuard ) .await?; // TODO - need to add a lock on the table to prevent concurrent updates as migrations are going through. @@ -710,7 +753,10 @@ pub async fn start_production_mode( .await; } - let _ = redis_client.stop_periodic_tasks(); + { + let mut redis_client = redis_client.lock().await; + let _ = redis_client.stop_periodic_tasks(); + } Ok(()) } From 8f69208c07c655ebc45fc68301e606c913516752 Mon Sep 17 00:00:00 2001 From: cjus Date: Mon, 14 Oct 2024 15:37:02 -0600 Subject: [PATCH 05/19] Switch behavior based leadership status --- apps/framework-cli/src/cli/routines.rs | 18 +++++++++++++----- 1 file changed, 13 insertions(+), 5 deletions(-) diff --git a/apps/framework-cli/src/cli/routines.rs b/apps/framework-cli/src/cli/routines.rs index b181c5a68..abf4bb506 100644 --- a/apps/framework-cli/src/cli/routines.rs +++ b/apps/framework-cli/src/cli/routines.rs @@ -337,12 +337,20 @@ async fn process_pubsub_message(message: String) { .unwrap_or(false) { if message.contains("") { - println!(" Migration start message received: {}", message); + println!(" This instance is the leader so ignoring the Migration start message: {}", message); } else if message.contains("") { - println!(" Migration end message received: {}", message); + println!(" This instance is the leader so ignoring the Migration end message received: {}", message); } else { - println!(" Received pubsub message: {}", message); + println!( + " This instance is the leader and received pubsub message: {}", + message + ); } + } else { + println!( + " This instance is not the leader and received pubsub message: {}", + message + ); } } @@ -446,7 +454,7 @@ pub async fn start_development_mode( api_changes_channel, metrics.clone(), &mut client, - &*redis_client.lock().await, // Dereference the MutexGuard + &*redis_client.lock().await, ) .await?; // TODO - need to add a lock on the table to prevent concurrent updates as migrations are going through. @@ -655,7 +663,7 @@ pub async fn start_production_mode( api_changes_channel, metrics.clone(), &mut client, - &*redis_client.lock().await, // Dereference the MutexGuard + &*redis_client.lock().await, ) .await?; // TODO - need to add a lock on the table to prevent concurrent updates as migrations are going through. From 061e823627b1bb6f3d12e1b89e0e620dc7c6b7f9 Mon Sep 17 00:00:00 2001 From: cjus Date: Tue, 15 Oct 2024 11:10:07 -0700 Subject: [PATCH 06/19] Remove use of global and pass in redis_client into callback --- apps/framework-cli/src/cli/routines.rs | 37 +++++++++++--------------- 1 file changed, 15 insertions(+), 22 deletions(-) diff --git a/apps/framework-cli/src/cli/routines.rs b/apps/framework-cli/src/cli/routines.rs index abf4bb506..69a1c6443 100644 --- a/apps/framework-cli/src/cli/routines.rs +++ b/apps/framework-cli/src/cli/routines.rs @@ -123,11 +123,6 @@ use super::settings::Features; use super::watcher::FileWatcher; use super::{Message, MessageType}; -use std::sync::LazyLock; - -static REDIS_CLIENT: LazyLock>>>> = - LazyLock::new(|| Mutex::new(None)); - pub mod auth; pub mod block; pub mod clean; @@ -303,9 +298,13 @@ async fn setup_redis_client(project: Arc) -> anyhow::Result) -> anyhow::Result>, +) -> anyhow::Result<()> { + let has_lock = { + let client = redis_client.lock().await; + client.has_lock("leadership").await? }; - if redis_client - .lock() - .await - .has_lock("leadership") - .await - .unwrap_or(false) - { + if has_lock { if message.contains("") { println!(" This instance is the leader so ignoring the Migration start message: {}", message); } else if message.contains("") { @@ -352,6 +344,7 @@ async fn process_pubsub_message(message: String) { message ); } + Ok(()) } fn start_leadership_lock_task(redis_client: Arc>, project: Arc) { From 60edb4bb5ae9aa5c4d8b95b0250a75276850adfb Mon Sep 17 00:00:00 2001 From: cjus Date: Tue, 15 Oct 2024 16:11:03 -0700 Subject: [PATCH 07/19] conver println! to info! --- apps/framework-cli/src/cli/routines.rs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/apps/framework-cli/src/cli/routines.rs b/apps/framework-cli/src/cli/routines.rs index 69a1c6443..692e531c3 100644 --- a/apps/framework-cli/src/cli/routines.rs +++ b/apps/framework-cli/src/cli/routines.rs @@ -329,17 +329,17 @@ async fn process_pubsub_message( if has_lock { if message.contains("") { - println!(" This instance is the leader so ignoring the Migration start message: {}", message); + info!(" This instance is the leader so ignoring the Migration start message: {}", message); } else if message.contains("") { - println!(" This instance is the leader so ignoring the Migration end message received: {}", message); + info!(" This instance is the leader so ignoring the Migration end message received: {}", message); } else { - println!( + info!( " This instance is the leader and received pubsub message: {}", message ); } } else { - println!( + info!( " This instance is not the leader and received pubsub message: {}", message ); From f54646bcde150f27db6ed786fb0b9bc61a4de994 Mon Sep 17 00:00:00 2001 From: cjus Date: Tue, 15 Oct 2024 17:00:32 -0700 Subject: [PATCH 08/19] Broadcast message when new leader --- apps/framework-cli/src/cli/routines.rs | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/apps/framework-cli/src/cli/routines.rs b/apps/framework-cli/src/cli/routines.rs index 0ca2b75e9..e65d2bf23 100644 --- a/apps/framework-cli/src/cli/routines.rs +++ b/apps/framework-cli/src/cli/routines.rs @@ -378,8 +378,10 @@ async fn manage_leadership_lock( let client = redis_client.lock().await; client.attempt_lock("leadership").await? }; - if acquired_lock { + let mut client = redis_client.lock().await; + client.broadcast_message("").await?; + info!("Obtained leadership lock, performing leadership tasks"); let project_clone = project.clone(); tokio::spawn(async move { From bb07e45a307a3e3d988146e1a2b9b50c4f5862b1 Mon Sep 17 00:00:00 2001 From: cjus Date: Thu, 17 Oct 2024 12:49:50 -0700 Subject: [PATCH 09/19] avoid pass an exra lock --- apps/framework-cli/src/cli/routines.rs | 4 ++-- apps/framework-cli/src/framework/core/execute.rs | 5 ++++- 2 files changed, 6 insertions(+), 3 deletions(-) diff --git a/apps/framework-cli/src/cli/routines.rs b/apps/framework-cli/src/cli/routines.rs index e65d2bf23..3434f1bda 100644 --- a/apps/framework-cli/src/cli/routines.rs +++ b/apps/framework-cli/src/cli/routines.rs @@ -449,7 +449,7 @@ pub async fn start_development_mode( api_changes_channel, metrics.clone(), &mut client, - &*redis_client.lock().await, + &redis_client, ) .await?; // TODO - need to add a lock on the table to prevent concurrent updates as migrations are going through. @@ -662,7 +662,7 @@ pub async fn start_production_mode( api_changes_channel, metrics.clone(), &mut client, - &*redis_client.lock().await, + &redis_client, ) .await?; // TODO - need to add a lock on the table to prevent concurrent updates as migrations are going through. diff --git a/apps/framework-cli/src/framework/core/execute.rs b/apps/framework-cli/src/framework/core/execute.rs index a6689616f..cc13e4863 100644 --- a/apps/framework-cli/src/framework/core/execute.rs +++ b/apps/framework-cli/src/framework/core/execute.rs @@ -2,6 +2,7 @@ use crate::infrastructure::redis::redis_client::RedisClient; use clickhouse_rs::ClientHandle; use std::sync::Arc; use tokio::sync::mpsc::Sender; +use tokio::sync::Mutex; use super::{infrastructure_map::ApiChange, plan::InfraPlan}; use crate::infrastructure::migration; @@ -50,7 +51,7 @@ pub async fn execute_initial_infra_change( api_changes_channel: Sender, metrics: Arc, clickhouse_client: &mut ClientHandle, - redis_client: &RedisClient, + redis_client: &Arc>, ) -> Result<(SyncingProcessesRegistry, ProcessRegistries), ExecutionError> { // This probably can be parallelized through Tokio Spawn olap::execute_changes(project, &plan.changes.olap_changes).await?; @@ -72,6 +73,8 @@ pub async fn execute_initial_infra_change( // Check if this process instance has the "leadership" lock if redis_client + .lock() + .await .has_lock("leadership") .await .map_err(ExecutionError::LeadershipCheckFailed)? From 2dd9d7bc7b88fb8cb7fcea0eccc786f6c6abf157 Mon Sep 17 00:00:00 2001 From: cjus Date: Thu, 17 Oct 2024 14:19:15 -0700 Subject: [PATCH 10/19] Cleanup --- .../src/infrastructure/redis/redis_client.rs | 43 +------------------ 1 file changed, 2 insertions(+), 41 deletions(-) diff --git a/apps/framework-cli/src/infrastructure/redis/redis_client.rs b/apps/framework-cli/src/infrastructure/redis/redis_client.rs index cc9069c75..970f29ddb 100644 --- a/apps/framework-cli/src/infrastructure/redis/redis_client.rs +++ b/apps/framework-cli/src/infrastructure/redis/redis_client.rs @@ -3,47 +3,8 @@ //! This module provides a Redis client implementation with support for leader election, //! presence updates, and message passing (Sending) and message queuing. //! -//! # Example Usage -//! -//! ```rust -//! use your_crate_name::infrastructure::redis::RedisClient; -//! -//! #[tokio::main] -//! async fn main() -> Result<(), Box> { -//! // Initialize the Redis client -//! let mut client = RedisClient::new("my_service").await?; -//! -//! // Start periodic tasks (presence updates and lock renewal) -//! client.start_periodic_tasks().await; -//! -//! // Attempt to gain leadership -//! let is_leader = client.attempt_leadership().await?; -//! println!("Is leader: {}", is_leader); -//! -//! // Send a message to another instance -//! client.send_message_to_instance("Hello", "target_instance_id").await?; -//! -//! // Broadcast a message to all instances -//! client.broadcast_message("Broadcast message").await?; -//! -//! // Post a message to the queue -//! client.post_queue_message("New task").await?; -//! -//! // Get a message from the queue -//! if let Some(message) = client.get_queue_message().await? { -//! println!("Received message: {}", message); -//! // Process the message... -//! client.mark_queue_message(&message, true).await?; -//! } -//! -//! // The client will automatically stop periodic tasks and release the lock (if leader) -//! // when it goes out of scope due to the Drop implementation -//! -//! Ok(()) -//! } -//! ``` -//! -//! Note: Make sure to set the MOOSE_REDIS_URL environment variable or the client will default to "redis://127.0.0.1:6379". +//! Note: Make sure to set the MOOSE_REDIS_URL environment variable or the client will +//! default to "redis://127.0.0.1:6379". use anyhow::{Context, Result}; use log::{error, info, warn}; use redis::aio::Connection as RedisConnection; From 90023cded67a561449dc78ab0f9490740b30d158 Mon Sep 17 00:00:00 2001 From: Nicolas Joseph Date: Tue, 15 Oct 2024 19:30:33 -0400 Subject: [PATCH 11/19] fix: remove process starting outside of the leadership lock (#1834) --- apps/framework-cli/src/framework/core/execute.rs | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/apps/framework-cli/src/framework/core/execute.rs b/apps/framework-cli/src/framework/core/execute.rs index cc13e4863..471fb704b 100644 --- a/apps/framework-cli/src/framework/core/execute.rs +++ b/apps/framework-cli/src/framework/core/execute.rs @@ -71,6 +71,14 @@ pub async fn execute_initial_infra_change( ); let mut process_registries = ProcessRegistries::new(project); + processes::execute_changes( + &mut syncing_processes_registry, + &mut process_registries, + &plan.target_infra_map.init_processes(), + metrics, + ) + .await?; + // Check if this process instance has the "leadership" lock if redis_client .lock() @@ -79,14 +87,6 @@ pub async fn execute_initial_infra_change( .await .map_err(ExecutionError::LeadershipCheckFailed)? { - processes::execute_changes( - &mut syncing_processes_registry, - &mut process_registries, - &plan.target_infra_map.init_processes(), - metrics, - ) - .await?; - // Execute migration changes only if we have the leadership lock migration::execute_changes(project, &plan.changes.initial_data_loads, clickhouse_client) .await From ef027b3a9fcaff2feca82fbf6964bfe4b1087595 Mon Sep 17 00:00:00 2001 From: Johanan Ottensooser Date: Tue, 15 Oct 2024 18:07:01 -0700 Subject: [PATCH 12/19] Update create-version.mdx (#1835) fix broken link --- .../framework-docs/src/pages/data-models/dcm/create-version.mdx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/framework-docs/src/pages/data-models/dcm/create-version.mdx b/apps/framework-docs/src/pages/data-models/dcm/create-version.mdx index cbbb3cf75..19697d339 100644 --- a/apps/framework-docs/src/pages/data-models/dcm/create-version.mdx +++ b/apps/framework-docs/src/pages/data-models/dcm/create-version.mdx @@ -101,7 +101,7 @@ export default function migrate(event: UserActivity_0_0): UserActivity_0_1 { } ``` -The setup of this function looks like a regular [Streaming Function](/processing-data): +The setup of this function looks like a regular [Streaming Function](https://docs.getmoose.dev/stream-processing): - The old version (`UserActivity_0_0`) is the input type. - The new version (`UserActivity_0_1`) is the output type. From 3829159adf42f96bf4182164473cc6cc74689111 Mon Sep 17 00:00:00 2001 From: Johanan Ottensooser Date: Tue, 15 Oct 2024 18:07:24 -0700 Subject: [PATCH 13/19] Update configure-webhook.mdx (#1832) allowed user to send --- apps/framework-docs/src/pages/learn-moose/configure-webhook.mdx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/framework-docs/src/pages/learn-moose/configure-webhook.mdx b/apps/framework-docs/src/pages/learn-moose/configure-webhook.mdx index a0d917d40..9d996f9ee 100644 --- a/apps/framework-docs/src/pages/learn-moose/configure-webhook.mdx +++ b/apps/framework-docs/src/pages/learn-moose/configure-webhook.mdx @@ -106,7 +106,7 @@ Click **"Add Webhook"** to save your configuration. ### Star & Un-star your Github Repository Go to your Github repository and star/un-star it. - + We’ll give it a star too! ### Check for `POST` and `SUCCESS` Messages in CLI From 2efc48282d876eeed4966b59b988695775ccea8f Mon Sep 17 00:00:00 2001 From: Nicolas Joseph Date: Wed, 16 Oct 2024 18:07:50 -0400 Subject: [PATCH 14/19] fix: metrics console back up (#1836) --- apps/framework-cli/src/cli/local_webserver.rs | 4 ++++ apps/framework-cli/src/metrics.rs | 23 ++++++++++++++++++- 2 files changed, 26 insertions(+), 1 deletion(-) diff --git a/apps/framework-cli/src/cli/local_webserver.rs b/apps/framework-cli/src/cli/local_webserver.rs index 5e4981437..07b3734f5 100644 --- a/apps/framework-cli/src/cli/local_webserver.rs +++ b/apps/framework-cli/src/cli/local_webserver.rs @@ -312,8 +312,12 @@ async fn log_route(req: Request) -> Response> { } async fn metrics_log_route(req: Request, metrics: Arc) -> Response> { + debug!("Received metrics log route"); + let body = to_reader(req).await; let parsed: Result = serde_json::from_reader(body); + debug!("Parsed metrics log route: {:?}", parsed); + if let Ok(MetricEvent::StreamingFunctionEvent { count_in, count_out, diff --git a/apps/framework-cli/src/metrics.rs b/apps/framework-cli/src/metrics.rs index 4345d2f63..47a39f75e 100644 --- a/apps/framework-cli/src/metrics.rs +++ b/apps/framework-cli/src/metrics.rs @@ -19,7 +19,7 @@ use crate::metrics_inserter::MetricsInserter; use crate::utilities::constants::{CLI_VERSION, CONTEXT, CTX_SESSION_ID}; use crate::utilities::decode_object; use chrono::{DateTime, Utc}; -use log::warn; +use log::{debug, warn}; const DEFAULT_ANONYMOUS_METRICS_URL: &str = "https://moosefood.514.dev/ingest/MooseSessionTelemetry/0.6"; @@ -49,6 +49,7 @@ pub enum MetricsErrors { } #[derive(Debug, Clone, Deserialize)] +#[serde(untagged)] pub enum MetricEvent { // GetMetricsRegistryAsString(tokio::sync::oneshot::Sender), IngestedEvent { @@ -104,6 +105,7 @@ pub struct Metrics { registry: Arc>, } +#[derive(Clone, Debug)] pub struct Statistics { pub http_latency_histogram_aggregate: Histogram, pub http_latency_histogram: Family, @@ -262,6 +264,7 @@ impl Metrics { registry.register( TOTAL_LATENCY, "Total latency of HTTP requests", + // Those clones are ok because this is cloning an Arc reference behind the scenes data.http_latency_histogram_aggregate.clone(), ); registry.register( @@ -322,6 +325,9 @@ impl Metrics { if export_metrics { let _ = metrics_inserter.insert(message.clone()).await; } + + debug!("Received Metrics Event: {:?}", message); + match message { MetricEvent::IngestedEvent { timestamp: _, @@ -338,9 +344,20 @@ impl Metrics { path: route.clone(), }) .inc_by(bytes); + data.http_ingested_request_count.inc(); data.http_ingested_total_bytes.inc_by(bytes); + data.http_latency_histogram + .get_or_create(&HTTPLabel { + method: method.clone(), + path: route.clone(), + }) + .observe(latency.as_secs_f64()); + + data.http_latency_histogram_aggregate + .observe(latency.as_secs_f64()); + data.http_ingested_latency_sum_ms .inc_by(latency.as_millis() as u64); @@ -366,8 +383,10 @@ impl Metrics { path: route.clone(), }) .observe(latency.as_secs_f64()); + data.http_latency_histogram_aggregate .observe(latency.as_secs_f64()); + data.http_consumed_latency_sum_ms .inc_by(latency.as_millis() as u64); @@ -433,6 +452,8 @@ impl Metrics { .inc_by(bytes); } }; + + debug!("Updated metrics: {:?}", data); } }); From eb2b5850830ebd910e7cb4f044fdca8267056a78 Mon Sep 17 00:00:00 2001 From: George Leung Date: Thu, 17 Oct 2024 13:37:11 -0700 Subject: [PATCH 15/19] fixes new clippy warnings in 1.82.0 (#1841) --- .../src/framework/core/execute.rs | 9 +- .../src/framework/core/infrastructure_map.rs | 100 ++++++++++-------- .../processes/consumption_registry.rs | 5 +- 3 files changed, 62 insertions(+), 52 deletions(-) diff --git a/apps/framework-cli/src/framework/core/execute.rs b/apps/framework-cli/src/framework/core/execute.rs index 471fb704b..a0a494de4 100644 --- a/apps/framework-cli/src/framework/core/execute.rs +++ b/apps/framework-cli/src/framework/core/execute.rs @@ -30,7 +30,7 @@ pub enum ExecutionError { StreamingChange(#[from] stream::StreamingChangesError), #[error("Failed to communicate with API")] - ApiChange(#[from] api::ApiChangeError), + ApiChange(#[from] Box), #[error("Failed to communicate with Sync Processes")] SyncProcessesChange(#[from] processes::SyncProcessChangesError), @@ -63,7 +63,8 @@ pub async fn execute_initial_infra_change( &plan.target_infra_map.init_api_endpoints(), api_changes_channel, ) - .await?; + .await + .map_err(Box::new)?; let mut syncing_processes_registry = SyncingProcessesRegistry::new( project.redpanda_config.clone(), @@ -112,7 +113,9 @@ pub async fn execute_online_change( // In prod, the webserver is part of the current process that gets spawned. As succh // it is initialized from 0 and we don't need to apply diffs to it. - api::execute_changes(&plan.changes.api_changes, api_changes_channel).await?; + api::execute_changes(&plan.changes.api_changes, api_changes_channel) + .await + .map_err(Box::new)?; processes::execute_changes( sync_processes_registry, diff --git a/apps/framework-cli/src/framework/core/infrastructure_map.rs b/apps/framework-cli/src/framework/core/infrastructure_map.rs index 44fb7ea8b..d36e4dcd7 100644 --- a/apps/framework-cli/src/framework/core/infrastructure_map.rs +++ b/apps/framework-cli/src/framework/core/infrastructure_map.rs @@ -30,9 +30,9 @@ pub struct PrimitiveSignature { #[derive(Debug, Clone)] pub enum Change { - Added(T), - Removed(T), - Updated { before: T, after: T }, + Added(Box), + Removed(Box), + Updated { before: Box, after: Box }, } #[allow(clippy::large_enum_variant)] @@ -338,16 +338,16 @@ impl InfrastructureMap { changes .streaming_engine_changes .push(StreamingChange::Topic(Change::::Updated { - before: topic.clone(), - after: target_topic.clone(), + before: Box::new(topic.clone()), + after: Box::new(target_topic.clone()), })); } } else { changes .streaming_engine_changes - .push(StreamingChange::Topic(Change::::Removed( + .push(StreamingChange::Topic(Change::::Removed(Box::new( topic.clone(), - ))); + )))); } } @@ -355,9 +355,9 @@ impl InfrastructureMap { if !self.topics.contains_key(id) { changes .streaming_engine_changes - .push(StreamingChange::Topic(Change::::Added( + .push(StreamingChange::Topic(Change::::Added(Box::new( topic.clone(), - ))); + )))); } } @@ -370,8 +370,8 @@ impl InfrastructureMap { if api_endpoint != target_api_endpoint { changes.api_changes.push(ApiChange::ApiEndpoint( Change::::Updated { - before: api_endpoint.clone(), - after: target_api_endpoint.clone(), + before: Box::new(api_endpoint.clone()), + after: Box::new(target_api_endpoint.clone()), }, )); } @@ -379,7 +379,7 @@ impl InfrastructureMap { changes .api_changes .push(ApiChange::ApiEndpoint(Change::::Removed( - api_endpoint.clone(), + Box::new(api_endpoint.clone()), ))); } } @@ -389,7 +389,7 @@ impl InfrastructureMap { changes .api_changes .push(ApiChange::ApiEndpoint(Change::::Added( - api_endpoint.clone(), + Box::new(api_endpoint.clone()), ))); } } @@ -404,14 +404,16 @@ impl InfrastructureMap { changes .olap_changes .push(OlapChange::Table(Change::::Updated { - before: table.clone(), - after: target_table.clone(), + before: Box::new(table.clone()), + after: Box::new(target_table.clone()), })); } } else { changes .olap_changes - .push(OlapChange::Table(Change::
::Removed(table.clone()))); + .push(OlapChange::Table(Change::
::Removed(Box::new( + table.clone(), + )))); } } @@ -419,7 +421,9 @@ impl InfrastructureMap { if !self.tables.contains_key(id) { changes .olap_changes - .push(OlapChange::Table(Change::
::Added(table.clone()))); + .push(OlapChange::Table(Change::
::Added(Box::new( + table.clone(), + )))); } } @@ -433,14 +437,16 @@ impl InfrastructureMap { changes .olap_changes .push(OlapChange::View(Change::::Updated { - before: view.clone(), - after: target_view.clone(), + before: Box::new(view.clone()), + after: Box::new(target_view.clone()), })); } } else { changes .olap_changes - .push(OlapChange::View(Change::::Removed(view.clone()))); + .push(OlapChange::View(Change::::Removed(Box::new( + view.clone(), + )))); } } @@ -448,7 +454,9 @@ impl InfrastructureMap { if !self.views.contains_key(id) { changes .olap_changes - .push(OlapChange::View(Change::::Added(view.clone()))); + .push(OlapChange::View(Change::::Added(Box::new( + view.clone(), + )))); } } @@ -466,8 +474,8 @@ impl InfrastructureMap { .push(ProcessChange::TopicToTableSyncProcess(Change::< TopicToTableSyncProcess, >::Updated { - before: topic_to_table_sync_process.clone(), - after: target_topic_to_table_sync_process.clone(), + before: Box::new(topic_to_table_sync_process.clone()), + after: Box::new(target_topic_to_table_sync_process.clone()), })); } } else { @@ -476,7 +484,7 @@ impl InfrastructureMap { .push(ProcessChange::TopicToTableSyncProcess(Change::< TopicToTableSyncProcess, >::Removed( - topic_to_table_sync_process.clone(), + Box::new(topic_to_table_sync_process.clone()), ))); } } @@ -488,7 +496,7 @@ impl InfrastructureMap { .push(ProcessChange::TopicToTableSyncProcess(Change::< TopicToTableSyncProcess, >::Added( - topic_to_table_sync_process.clone(), + Box::new(topic_to_table_sync_process.clone()), ))); } } @@ -507,8 +515,8 @@ impl InfrastructureMap { .push(ProcessChange::TopicToTopicSyncProcess(Change::< TopicToTopicSyncProcess, >::Updated { - before: topic_to_topic_sync_process.clone(), - after: target_topic_to_topic_sync_process.clone(), + before: Box::new(topic_to_topic_sync_process.clone()), + after: Box::new(target_topic_to_topic_sync_process.clone()), })); } } else { @@ -517,7 +525,7 @@ impl InfrastructureMap { .push(ProcessChange::TopicToTopicSyncProcess(Change::< TopicToTopicSyncProcess, >::Removed( - topic_to_topic_sync_process.clone(), + Box::new(topic_to_topic_sync_process.clone()), ))); } } @@ -529,7 +537,7 @@ impl InfrastructureMap { .push(ProcessChange::TopicToTopicSyncProcess(Change::< TopicToTopicSyncProcess, >::Added( - topic_to_topic_sync_process.clone(), + Box::new(topic_to_topic_sync_process.clone()), ))); } } @@ -548,15 +556,15 @@ impl InfrastructureMap { .processes_changes .push(ProcessChange::FunctionProcess( Change::::Updated { - before: function_process.clone(), - after: target_function_process.clone(), + before: Box::new(function_process.clone()), + after: Box::new(target_function_process.clone()), }, )); } else { changes .processes_changes .push(ProcessChange::FunctionProcess( - Change::::Removed(function_process.clone()), + Change::::Removed(Box::new(function_process.clone())), )); } } @@ -566,7 +574,7 @@ impl InfrastructureMap { changes .processes_changes .push(ProcessChange::FunctionProcess( - Change::::Added(function_process.clone()), + Change::::Added(Box::new(function_process.clone())), )); } } @@ -607,8 +615,8 @@ impl InfrastructureMap { // currently we assume there is always a change and restart the processes changes.processes_changes.push(ProcessChange::OlapProcess( Change::::Updated { - before: OlapProcess {}, - after: OlapProcess {}, + before: Box::new(OlapProcess {}), + after: Box::new(OlapProcess {}), }, )); @@ -626,8 +634,8 @@ impl InfrastructureMap { .push(ProcessChange::ConsumptionApiWebServer(Change::< ConsumptionApiWebServer, >::Updated { - before: ConsumptionApiWebServer {}, - after: ConsumptionApiWebServer {}, + before: Box::new(ConsumptionApiWebServer {}), + after: Box::new(ConsumptionApiWebServer {}), })); changes @@ -656,7 +664,7 @@ impl InfrastructureMap { pub fn init_topics(&self) -> Vec { self.topics .values() - .map(|topic| StreamingChange::Topic(Change::::Added(topic.clone()))) + .map(|topic| StreamingChange::Topic(Change::::Added(Box::new(topic.clone())))) .collect() } @@ -664,7 +672,7 @@ impl InfrastructureMap { self.api_endpoints .values() .map(|api_endpoint| { - ApiChange::ApiEndpoint(Change::::Added(api_endpoint.clone())) + ApiChange::ApiEndpoint(Change::::Added(Box::new(api_endpoint.clone()))) }) .collect() } @@ -672,7 +680,7 @@ impl InfrastructureMap { pub fn init_tables(&self) -> Vec { self.tables .values() - .map(|table| OlapChange::Table(Change::
::Added(table.clone()))) + .map(|table| OlapChange::Table(Change::
::Added(Box::new(table.clone())))) .collect() } @@ -682,7 +690,7 @@ impl InfrastructureMap { .values() .map(|topic_to_table_sync_process| { ProcessChange::TopicToTableSyncProcess(Change::::Added( - topic_to_table_sync_process.clone(), + Box::new(topic_to_table_sync_process.clone()), )) }) .collect(); @@ -692,7 +700,7 @@ impl InfrastructureMap { .values() .map(|topic_to_table_sync_process| { ProcessChange::TopicToTopicSyncProcess(Change::::Added( - topic_to_table_sync_process.clone(), + Box::new(topic_to_table_sync_process.clone()), )) }) .collect(); @@ -702,9 +710,9 @@ impl InfrastructureMap { .function_processes .values() .map(|function_process| { - ProcessChange::FunctionProcess(Change::::Added( + ProcessChange::FunctionProcess(Change::::Added(Box::new( function_process.clone(), - )) + ))) }) .collect(); @@ -712,13 +720,13 @@ impl InfrastructureMap { // TODO Change this when we have multiple processes for aggregations topic_to_table_process_changes.push(ProcessChange::OlapProcess( - Change::::Added(OlapProcess {}), + Change::::Added(Box::new(OlapProcess {})), )); topic_to_table_process_changes.push(ProcessChange::ConsumptionApiWebServer(Change::< ConsumptionApiWebServer, >::Added( - ConsumptionApiWebServer {}, + Box::new(ConsumptionApiWebServer {}), ))); topic_to_table_process_changes diff --git a/apps/framework-cli/src/infrastructure/processes/consumption_registry.rs b/apps/framework-cli/src/infrastructure/processes/consumption_registry.rs index e8cbd586f..b898e8efb 100644 --- a/apps/framework-cli/src/infrastructure/processes/consumption_registry.rs +++ b/apps/framework-cli/src/infrastructure/processes/consumption_registry.rs @@ -72,9 +72,8 @@ impl ConsumptionProcessRegistry { pub async fn stop(&mut self) -> Result<(), ConsumptionError> { info!("Stopping consumption..."); - match &self.api_process { - Some(child) => kill_child(child).await?, - None => (), + if let Some(child) = &self.api_process { + kill_child(child).await? }; self.api_process = None; From f33ad2b3d377bae51083d8bb7e4ec530090bfd3d Mon Sep 17 00:00:00 2001 From: George Leung Date: Thu, 17 Oct 2024 13:48:11 -0700 Subject: [PATCH 16/19] backticks around each field in primary key (#1840) --- .../src/infrastructure/olap/clickhouse/queries.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/apps/framework-cli/src/infrastructure/olap/clickhouse/queries.rs b/apps/framework-cli/src/infrastructure/olap/clickhouse/queries.rs index 070fc1d50..30578be4c 100644 --- a/apps/framework-cli/src/infrastructure/olap/clickhouse/queries.rs +++ b/apps/framework-cli/src/infrastructure/olap/clickhouse/queries.rs @@ -114,7 +114,7 @@ CREATE TABLE IF NOT EXISTS `{{db_name}}`.`{{table_name}}` {{/each}} ) ENGINE = {{engine}} -{{#if primary_key_string}}PRIMARY KEY (`{{primary_key_string}}`) {{/if}} +{{#if primary_key_string}}PRIMARY KEY ({{primary_key_string}}) {{/if}} {{#if order_by_string}}ORDER BY ({{order_by_string}}) {{/if}} "#; @@ -150,7 +150,7 @@ pub fn create_table_query( "table_name": table.name, "fields": builds_field_context(&table.columns)?, "primary_key_string": if !primary_key.is_empty() { - Some(primary_key.join(", ")) + Some(format!("`{}`", primary_key.join("`, `"))) } else { None }, From c5d61e692b9f39e03c52c3615fdc5e2c979ee5c8 Mon Sep 17 00:00:00 2001 From: George Leung Date: Thu, 17 Oct 2024 13:48:29 -0700 Subject: [PATCH 17/19] Import csv with types (#1837) --- .../src/framework/bulk_import.rs | 35 ++++++++++++++++++- 1 file changed, 34 insertions(+), 1 deletion(-) diff --git a/apps/framework-cli/src/framework/bulk_import.rs b/apps/framework-cli/src/framework/bulk_import.rs index 2aa7d9a10..06cc1a666 100644 --- a/apps/framework-cli/src/framework/bulk_import.rs +++ b/apps/framework-cli/src/framework/bulk_import.rs @@ -1,7 +1,9 @@ use crate::framework::core::code_loader::FrameworkObject; +use crate::framework::core::infrastructure::table::ColumnType; use anyhow::bail; use itertools::Itertools; use serde::__private::from_utf8_lossy; +use serde_json::json; use std::collections::HashMap; use std::path::Path; @@ -16,6 +18,13 @@ pub async fn import_csv_file( let client = reqwest::Client::new(); + let types: HashMap = data_model + .data_model + .columns + .iter() + .map(|col| (col.name.clone(), col.data_type.clone())) + .collect(); + for chunks in &rdr.records().chunks(1024) { let mut s = "[".to_string(); let mut start = true; @@ -31,7 +40,31 @@ pub async fn import_csv_file( let mut json_map = HashMap::new(); for (i, key) in headers.iter().enumerate() { if let Some(value) = record.get(i) { - json_map.insert(key, value); + if let Some(t) = types.get(key) { + match t { + ColumnType::String | ColumnType::DateTime | ColumnType::Enum(_) => { + json_map.insert(key, json!(value)); + } + ColumnType::Boolean => { + json_map.insert(key, json!(value.parse::()?)); + } + ColumnType::Int | ColumnType::BigInt => { + json_map.insert(key, json!(value.parse::()?)); + } + ColumnType::Float => { + json_map.insert(key, json!(value.parse::()?)); + } + ColumnType::Decimal => { + json_map.insert(key, json!(value.parse::()?)); + } + ColumnType::Array(_) + | ColumnType::Nested(_) + | ColumnType::Json + | ColumnType::Bytes => { + bail!("CSV importing does not support complex types"); + } + } + } }; } s.push_str(&serde_json::to_string(&json_map)?); From 79314c93e946ae6fe06bec30ec6ff23648ceab0f Mon Sep 17 00:00:00 2001 From: George Leung Date: Thu, 17 Oct 2024 14:00:25 -0700 Subject: [PATCH 18/19] accept float unix timestamp (#1839) --- apps/framework-cli/src/utilities/validate_passthrough.rs | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/apps/framework-cli/src/utilities/validate_passthrough.rs b/apps/framework-cli/src/utilities/validate_passthrough.rs index 4f8dcfa41..687314c2c 100644 --- a/apps/framework-cli/src/utilities/validate_passthrough.rs +++ b/apps/framework-cli/src/utilities/validate_passthrough.rs @@ -195,6 +195,15 @@ impl<'de, 'a, S: SerializeValue> Visitor<'de> for &mut ValueVisitor<'a, S> { E: Error, { match self.t { + ColumnType::DateTime => { + let seconds = v.trunc() as i64; + let nanos = ((v.fract() * 1_000_000_000.0).round() as u32).min(999_999_999); + let date = chrono::DateTime::from_timestamp(seconds, nanos) + .ok_or(E::custom("Invalid timestamp"))?; + self.write_to + .serialize_value(&date.to_rfc3339_opts(chrono::SecondsFormat::Nanos, true)) + .map_err(Error::custom) + } ColumnType::Float => self.write_to.serialize_value(&v).map_err(Error::custom), _ => Err(Error::invalid_type(serde::de::Unexpected::Float(v), &self)), } From 79c963908d653887fe2132c1ee9300af8cc27a46 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Sat, 19 Oct 2024 14:27:50 -0700 Subject: [PATCH 19/19] Bump next from 14.2.4 to 14.2.10 in the npm_and_yarn group across 1 directory (#1811) * Bump next in the npm_and_yarn group across 1 directory Bumps the npm_and_yarn group with 1 update in the / directory: [next](https://github.com/vercel/next.js). Updates `next` from 14.2.4 to 14.2.10 - [Release notes](https://github.com/vercel/next.js/releases) - [Changelog](https://github.com/vercel/next.js/blob/canary/release.js) - [Commits](https://github.com/vercel/next.js/compare/v14.2.4...v14.2.10) --- updated-dependencies: - dependency-name: next dependency-type: direct:production dependency-group: npm_and_yarn ... Signed-off-by: dependabot[bot] * pnpm exec prettier --write pnpm-lock.yaml --------- Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> Co-authored-by: George Leung --- apps/framework-docs/package.json | 2 +- pnpm-lock.yaml | 349 +++++++------------------------ 2 files changed, 80 insertions(+), 271 deletions(-) diff --git a/apps/framework-docs/package.json b/apps/framework-docs/package.json index f5c64c5a0..0b7ab8451 100644 --- a/apps/framework-docs/package.json +++ b/apps/framework-docs/package.json @@ -15,7 +15,7 @@ "@sentry/nextjs": "^7.106.0", "lucide-react": "^0.427.0", "mixpanel": "^0.18.0", - "next": "^14.2.4", + "next": "^14.2.10", "nextra": "^2.13.2", "nextra-theme-docs": "^2.13.2", "react": "^18.2.0", diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 6f65d0bbc..b125c9a9f 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -81,10 +81,10 @@ importers: version: 0.18.0 next: specifier: 14.2.10 - version: 14.2.10(react-dom@18.3.1(react@18.3.1))(react@18.3.1) + version: 14.2.10(@babel/core@7.24.5)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) next-themes: specifier: ^0.2.1 - version: 0.2.1(next@14.2.10(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(react-dom@18.3.1(react@18.3.1))(react@18.3.1) + version: 0.2.1(next@14.2.10(@babel/core@7.24.5)(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(react-dom@18.3.1(react@18.3.1))(react@18.3.1) react: specifier: ^18 version: 18.3.1 @@ -109,7 +109,7 @@ importers: version: 2.1.3(react@18.3.1) "@sentry/nextjs": specifier: ^7.106.0 - version: 7.114.0(next@14.2.10(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(react@18.3.1)(webpack@5.93.0) + version: 7.114.0(next@14.2.10(@babel/core@7.24.5)(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(react@18.3.1)(webpack@5.93.0) "@types/mdx": specifier: ^2.0.12 version: 2.0.13 @@ -206,7 +206,7 @@ importers: version: link:../../packages/event-capture "@sentry/nextjs": specifier: ^7.106.0 - version: 7.114.0(next@14.2.4(@babel/core@7.24.5)(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(react@18.3.1)(webpack@5.93.0) + version: 7.114.0(next@14.2.10(@babel/core@7.24.5)(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(react@18.3.1)(webpack@5.93.0) lucide-react: specifier: ^0.427.0 version: 0.427.0(react@18.3.1) @@ -214,14 +214,14 @@ importers: specifier: ^0.18.0 version: 0.18.0 next: - specifier: ^14.2.4 - version: 14.2.4(@babel/core@7.24.5)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) + specifier: ^14.2.10 + version: 14.2.10(@babel/core@7.24.5)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) nextra: specifier: ^2.13.2 - version: 2.13.4(next@14.2.4(@babel/core@7.24.5)(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(react-dom@18.3.1(react@18.3.1))(react@18.3.1) + version: 2.13.4(next@14.2.10(@babel/core@7.24.5)(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(react-dom@18.3.1(react@18.3.1))(react@18.3.1) nextra-theme-docs: specifier: ^2.13.2 - version: 2.13.4(next@14.2.4(@babel/core@7.24.5)(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(nextra@2.13.4(next@14.2.4(@babel/core@7.24.5)(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(react-dom@18.3.1(react@18.3.1))(react@18.3.1) + version: 2.13.4(next@14.2.10(@babel/core@7.24.5)(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(nextra@2.13.4(next@14.2.10(@babel/core@7.24.5)(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(react-dom@18.3.1(react@18.3.1))(react@18.3.1) react: specifier: ^18.2.0 version: 18.3.1 @@ -282,7 +282,7 @@ importers: dependencies: "@514labs/moose-lib": specifier: latest - version: 0.3.636(@types/node@20.12.12) + version: 0.3.650(@types/node@20.12.12) "@clickhouse/client-web": specifier: 1.1.0 version: 1.1.0 @@ -301,7 +301,7 @@ importers: devDependencies: "@514labs/moose-cli": specifier: latest - version: 0.3.634 + version: 0.3.650 "@types/async": specifier: ^3.2.24 version: 3.2.24 @@ -358,10 +358,10 @@ importers: version: 0.18.0 next: specifier: 14.2.10 - version: 14.2.10(react-dom@18.3.1(react@18.3.1))(react@18.3.1) + version: 14.2.10(@babel/core@7.24.5)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) next-themes: specifier: ^0.2.1 - version: 0.2.1(next@14.2.10(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(react-dom@18.3.1(react@18.3.1))(react@18.3.1) + version: 0.2.1(next@14.2.10(@babel/core@7.24.5)(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(react-dom@18.3.1(react@18.3.1))(react@18.3.1) next-video: specifier: ^1.0.6 version: 1.0.6(@types/react-dom@18.3.0)(@types/react@18.3.1)(next@14.2.10(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(react-dom@18.3.1(react@18.3.1))(react@18.3.1) @@ -386,7 +386,7 @@ importers: version: 2.1.3(react@18.3.1) "@sentry/nextjs": specifier: ^7.106.0 - version: 7.114.0(next@14.2.10(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(react@18.3.1)(webpack@5.93.0) + version: 7.114.0(next@14.2.10(@babel/core@7.24.5)(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(react@18.3.1)(webpack@5.93.0) "@types/node": specifier: ^20 version: 20.12.12 @@ -467,7 +467,7 @@ importers: version: 0.401.0(react@18.3.1) next: specifier: 14.2.10 - version: 14.2.10(react-dom@18.3.1(react@18.3.1))(react@18.3.1) + version: 14.2.10(@babel/core@7.24.5)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) next-auth: specifier: ^4.24.7 version: 4.24.7(next@14.2.10(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(react-dom@18.3.1(react@18.3.1))(react@18.3.1) @@ -592,7 +592,7 @@ importers: version: 0.344.0(react@18.3.1) next: specifier: 14.2.10 - version: 14.2.10(react-dom@18.3.1(react@18.3.1))(react@18.3.1) + version: 14.2.10(@babel/core@7.24.5)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) next-auth: specifier: ^4.24.7 version: 4.24.7(next@14.2.10(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(react-dom@18.3.1(react@18.3.1))(react@18.3.1) @@ -663,7 +663,7 @@ importers: devDependencies: "@sentry/nextjs": specifier: ^7.106.0 - version: 7.114.0(next@14.2.10(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(react@18.3.1)(webpack@5.93.0) + version: 7.114.0(next@14.2.10(@babel/core@7.24.5)(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(react@18.3.1)(webpack@5.93.0) "@types/node": specifier: ^20.14.5 version: 20.14.5 @@ -741,10 +741,10 @@ importers: version: 0.18.0 next: specifier: 14.2.10 - version: 14.2.10(react-dom@18.3.1(react@18.3.1))(react@18.3.1) + version: 14.2.10(@babel/core@7.24.5)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) next-themes: specifier: ^0.2.1 - version: 0.2.1(next@14.2.10(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(react-dom@18.3.1(react@18.3.1))(react@18.3.1) + version: 0.2.1(next@14.2.10(@babel/core@7.24.5)(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(react-dom@18.3.1(react@18.3.1))(react@18.3.1) react: specifier: ^18 version: 18.3.1 @@ -769,7 +769,7 @@ importers: version: 2.1.3(react@18.3.1) "@sentry/nextjs": specifier: ^7.106.0 - version: 7.114.0(next@14.2.10(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(react@18.3.1)(webpack@5.93.0) + version: 7.114.0(next@14.2.10(@babel/core@7.24.5)(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(react@18.3.1)(webpack@5.93.0) "@types/node": specifier: ^20 version: 20.14.5 @@ -826,7 +826,7 @@ importers: version: 0.18.0 next: specifier: 14.2.10 - version: 14.2.10(react-dom@18.3.1(react@18.3.1))(react@18.3.1) + version: 14.2.10(@babel/core@7.24.5)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) react: specifier: ^18 version: 18.3.1 @@ -898,10 +898,10 @@ packages: cpu: [arm64] os: [darwin] - "@514labs/moose-cli-darwin-arm64@0.3.634": + "@514labs/moose-cli-darwin-arm64@0.3.650": resolution: { - integrity: sha512-JA83I1+1V+OqLcjYQ3cs6M2Bb0MAV7F7G4Qt75FAlrg0gYMzykwNodgxmMY5rh7J97zbvGf7yA07Ibh6Vy4upg==, + integrity: sha512-EwwJBDr22ICMJmiXDoHdWl1wrzPhhCQLx661rrSrdihbipnpYhVayjwvRc1duodLMqvsKhyx8mNhpC8OPzFp9w==, } cpu: [arm64] os: [darwin] @@ -914,10 +914,10 @@ packages: cpu: [x64] os: [darwin] - "@514labs/moose-cli-darwin-x64@0.3.634": + "@514labs/moose-cli-darwin-x64@0.3.650": resolution: { - integrity: sha512-UUooF0ZVys07lAc2ZR/GVHL8dwRHvchblpg5u6mbvVjpf+jq1qcsQY5THrX5Bx3UbelLN8UiqXDgvDhPQg3T/w==, + integrity: sha512-qN7aRdox47VrMg4RQsHSzUw+Ld3HHtgGVV7B3kiWjhZ2czz0FzJK1poZrxZPIXuLer8okPujuDmAQy+vOPx1+A==, } cpu: [x64] os: [darwin] @@ -930,10 +930,10 @@ packages: cpu: [arm64] os: [linux] - "@514labs/moose-cli-linux-arm64@0.3.634": + "@514labs/moose-cli-linux-arm64@0.3.650": resolution: { - integrity: sha512-D/qL8MjKXysceFegcrU7NI338xQMT6O7j9GlOQQ2QBju4BLgKOr7CySpHG7w5w+8oUhCno7hCQKGixtzbqFmUw==, + integrity: sha512-Svf98vxoHvVjpd4Zy5TagHlHrA6Meh9vnCmhwcQgusFqLqw8i5vJKbGoqHGctxx6SbGyB2jdOSLwCjghhxaq4w==, } cpu: [arm64] os: [linux] @@ -946,10 +946,10 @@ packages: cpu: [x64] os: [linux] - "@514labs/moose-cli-linux-x64@0.3.634": + "@514labs/moose-cli-linux-x64@0.3.650": resolution: { - integrity: sha512-pCqU7Tij1nz3q3KN1DxqiQNDoPNQwISEOMpeRv3J7wA8H4Srxl7MLEeZpwaX/8Zhen77AIGwQLT4ItZsXhAaUg==, + integrity: sha512-+72HpBMpdhN3GHaeej1OvjyKHakS2npij3x8KDx1kFjY44TpveT2BZFPjF8XxCPoH30zU/KkcBtvOn/5JQCwOg==, } cpu: [x64] os: [linux] @@ -961,17 +961,17 @@ packages: } hasBin: true - "@514labs/moose-cli@0.3.634": + "@514labs/moose-cli@0.3.650": resolution: { - integrity: sha512-rXpHzyGdZ0X3uy8g/XtbMDe/SxG9uQ593S5CcWxpVs5J/IqbPWzMKFJW68iZz3/Eoba8WuEl5T3APOHieLE0LQ==, + integrity: sha512-yapur8l33hARYOSFTv5IsakAaC4Y64K21SN+vkVFlHdcr088sMUteTLfSfP9mB2ArSpvxL0z+n28ojl+0Cm7Jw==, } hasBin: true - "@514labs/moose-lib@0.3.636": + "@514labs/moose-lib@0.3.650": resolution: { - integrity: sha512-H+FyXyB1Ri4NLP7LHha+UQyNvbOUzgcwY5CHQFcM9hycQC222baN2opAnyKxRXSBLnEVdbIdxUyC3SHajvm4FA==, + integrity: sha512-G8q8m2JZrKTu+flS992bqiC22o/SNFcCC/YBoeRyabkoZ6jYr1huNjH2kddP51qAXAWHcXuhMC8WOfvExbfGwg==, } hasBin: true @@ -2461,12 +2461,6 @@ packages: integrity: sha512-W7fd7IbkfmeeY2gXrzJYDx8D2lWKbVoTIj1o1ScPHNzvp30s1AuoEFSdr39bC5sjxJaxTtq3OTCZboNp0lNWHA==, } - "@next/env@14.2.4": - resolution: - { - integrity: sha512-3EtkY5VDkuV2+lNmKlbkibIJxcO4oIHEhBWne6PaAp+76J9KoSsGvNikp6ivzAT8dhhBMYrm6op2pS1ApG0Hzg==, - } - "@next/eslint-plugin-next@13.5.6": resolution: { @@ -2514,15 +2508,6 @@ packages: cpu: [arm64] os: [darwin] - "@next/swc-darwin-arm64@14.2.4": - resolution: - { - integrity: sha512-AH3mO4JlFUqsYcwFUHb1wAKlebHU/Hv2u2kb1pAuRanDZ7pD/A/KPD98RHZmwsJpdHQwfEc/06mgpSzwrJYnNg==, - } - engines: { node: ">= 10" } - cpu: [arm64] - os: [darwin] - "@next/swc-darwin-x64@14.2.10": resolution: { @@ -2532,15 +2517,6 @@ packages: cpu: [x64] os: [darwin] - "@next/swc-darwin-x64@14.2.4": - resolution: - { - integrity: sha512-QVadW73sWIO6E2VroyUjuAxhWLZWEpiFqHdZdoQ/AMpN9YWGuHV8t2rChr0ahy+irKX5mlDU7OY68k3n4tAZTg==, - } - engines: { node: ">= 10" } - cpu: [x64] - os: [darwin] - "@next/swc-linux-arm64-gnu@14.2.10": resolution: { @@ -2550,15 +2526,6 @@ packages: cpu: [arm64] os: [linux] - "@next/swc-linux-arm64-gnu@14.2.4": - resolution: - { - integrity: sha512-KT6GUrb3oyCfcfJ+WliXuJnD6pCpZiosx2X3k66HLR+DMoilRb76LpWPGb4tZprawTtcnyrv75ElD6VncVamUQ==, - } - engines: { node: ">= 10" } - cpu: [arm64] - os: [linux] - "@next/swc-linux-arm64-musl@14.2.10": resolution: { @@ -2568,15 +2535,6 @@ packages: cpu: [arm64] os: [linux] - "@next/swc-linux-arm64-musl@14.2.4": - resolution: - { - integrity: sha512-Alv8/XGSs/ytwQcbCHwze1HmiIkIVhDHYLjczSVrf0Wi2MvKn/blt7+S6FJitj3yTlMwMxII1gIJ9WepI4aZ/A==, - } - engines: { node: ">= 10" } - cpu: [arm64] - os: [linux] - "@next/swc-linux-x64-gnu@14.2.10": resolution: { @@ -2586,15 +2544,6 @@ packages: cpu: [x64] os: [linux] - "@next/swc-linux-x64-gnu@14.2.4": - resolution: - { - integrity: sha512-ze0ShQDBPCqxLImzw4sCdfnB3lRmN3qGMB2GWDRlq5Wqy4G36pxtNOo2usu/Nm9+V2Rh/QQnrRc2l94kYFXO6Q==, - } - engines: { node: ">= 10" } - cpu: [x64] - os: [linux] - "@next/swc-linux-x64-musl@14.2.10": resolution: { @@ -2604,15 +2553,6 @@ packages: cpu: [x64] os: [linux] - "@next/swc-linux-x64-musl@14.2.4": - resolution: - { - integrity: sha512-8dwC0UJoc6fC7PX70csdaznVMNr16hQrTDAMPvLPloazlcaWfdPogq+UpZX6Drqb1OBlwowz8iG7WR0Tzk/diQ==, - } - engines: { node: ">= 10" } - cpu: [x64] - os: [linux] - "@next/swc-win32-arm64-msvc@14.2.10": resolution: { @@ -2622,15 +2562,6 @@ packages: cpu: [arm64] os: [win32] - "@next/swc-win32-arm64-msvc@14.2.4": - resolution: - { - integrity: sha512-jxyg67NbEWkDyvM+O8UDbPAyYRZqGLQDTPwvrBBeOSyVWW/jFQkQKQ70JDqDSYg1ZDdl+E3nkbFbq8xM8E9x8A==, - } - engines: { node: ">= 10" } - cpu: [arm64] - os: [win32] - "@next/swc-win32-ia32-msvc@14.2.10": resolution: { @@ -2640,15 +2571,6 @@ packages: cpu: [ia32] os: [win32] - "@next/swc-win32-ia32-msvc@14.2.4": - resolution: - { - integrity: sha512-twrmN753hjXRdcrZmZttb/m5xaCBFa48Dt3FbeEItpJArxriYDunWxJn+QFXdJ3hPkm4u7CKxncVvnmgQMY1ag==, - } - engines: { node: ">= 10" } - cpu: [ia32] - os: [win32] - "@next/swc-win32-x64-msvc@14.2.10": resolution: { @@ -2658,15 +2580,6 @@ packages: cpu: [x64] os: [win32] - "@next/swc-win32-x64-msvc@14.2.4": - resolution: - { - integrity: sha512-tkLrjBzqFTP8DVrAAQmZelEahfR9OxWpFR++vAI9FBhCiIxtwHwBHC23SBHCTURBtwB4kc/x44imVOnkKGNVGg==, - } - engines: { node: ">= 10" } - cpu: [x64] - os: [win32] - "@next/third-parties@14.2.3": resolution: { @@ -10290,27 +10203,6 @@ packages: sass: optional: true - next@14.2.4: - resolution: - { - integrity: sha512-R8/V7vugY+822rsQGQCjoLhMuC9oFj9SOi4Cl4b2wjDrseD0LRZ10W7R6Czo4w9ZznVSshKjuIomsRjvm9EKJQ==, - } - engines: { node: ">=18.17.0" } - hasBin: true - peerDependencies: - "@opentelemetry/api": ^1.1.0 - "@playwright/test": ^1.41.2 - react: ^18.2.0 - react-dom: ^18.2.0 - sass: ^1.3.0 - peerDependenciesMeta: - "@opentelemetry/api": - optional: true - "@playwright/test": - optional: true - sass: - optional: true - nextra-theme-docs@2.13.4: resolution: { @@ -13045,25 +12937,25 @@ snapshots: "@514labs/moose-cli-darwin-arm64@0.3.205": optional: true - "@514labs/moose-cli-darwin-arm64@0.3.634": + "@514labs/moose-cli-darwin-arm64@0.3.650": optional: true "@514labs/moose-cli-darwin-x64@0.3.205": optional: true - "@514labs/moose-cli-darwin-x64@0.3.634": + "@514labs/moose-cli-darwin-x64@0.3.650": optional: true "@514labs/moose-cli-linux-arm64@0.3.205": optional: true - "@514labs/moose-cli-linux-arm64@0.3.634": + "@514labs/moose-cli-linux-arm64@0.3.650": optional: true "@514labs/moose-cli-linux-x64@0.3.205": optional: true - "@514labs/moose-cli-linux-x64@0.3.634": + "@514labs/moose-cli-linux-x64@0.3.650": optional: true "@514labs/moose-cli@0.3.205": @@ -13073,14 +12965,14 @@ snapshots: "@514labs/moose-cli-linux-arm64": 0.3.205 "@514labs/moose-cli-linux-x64": 0.3.205 - "@514labs/moose-cli@0.3.634": + "@514labs/moose-cli@0.3.650": optionalDependencies: - "@514labs/moose-cli-darwin-arm64": 0.3.634 - "@514labs/moose-cli-darwin-x64": 0.3.634 - "@514labs/moose-cli-linux-arm64": 0.3.634 - "@514labs/moose-cli-linux-x64": 0.3.634 + "@514labs/moose-cli-darwin-arm64": 0.3.650 + "@514labs/moose-cli-darwin-x64": 0.3.650 + "@514labs/moose-cli-linux-arm64": 0.3.650 + "@514labs/moose-cli-linux-x64": 0.3.650 - "@514labs/moose-lib@0.3.636(@types/node@20.12.12)": + "@514labs/moose-lib@0.3.650(@types/node@20.12.12)": dependencies: "@clickhouse/client-web": 1.5.0 fastq: 1.17.1 @@ -13161,8 +13053,8 @@ snapshots: "@aws-crypto/sha1-browser": 3.0.0 "@aws-crypto/sha256-browser": 3.0.0 "@aws-crypto/sha256-js": 3.0.0 - "@aws-sdk/client-sso-oidc": 3.574.0 - "@aws-sdk/client-sts": 3.574.0(@aws-sdk/client-sso-oidc@3.574.0) + "@aws-sdk/client-sso-oidc": 3.574.0(@aws-sdk/client-sts@3.574.0) + "@aws-sdk/client-sts": 3.574.0 "@aws-sdk/core": 3.572.0 "@aws-sdk/credential-provider-node": 3.572.0(@aws-sdk/client-sso-oidc@3.574.0)(@aws-sdk/client-sts@3.574.0) "@aws-sdk/middleware-bucket-endpoint": 3.568.0 @@ -13219,11 +13111,11 @@ snapshots: transitivePeerDependencies: - aws-crt - "@aws-sdk/client-sso-oidc@3.574.0": + "@aws-sdk/client-sso-oidc@3.574.0(@aws-sdk/client-sts@3.574.0)": dependencies: "@aws-crypto/sha256-browser": 3.0.0 "@aws-crypto/sha256-js": 3.0.0 - "@aws-sdk/client-sts": 3.574.0(@aws-sdk/client-sso-oidc@3.574.0) + "@aws-sdk/client-sts": 3.574.0 "@aws-sdk/core": 3.572.0 "@aws-sdk/credential-provider-node": 3.572.0(@aws-sdk/client-sso-oidc@3.574.0)(@aws-sdk/client-sts@3.574.0) "@aws-sdk/middleware-host-header": 3.567.0 @@ -13262,6 +13154,7 @@ snapshots: "@smithy/util-utf8": 2.3.0 tslib: 2.6.2 transitivePeerDependencies: + - "@aws-sdk/client-sts" - aws-crt "@aws-sdk/client-sso@3.572.0": @@ -13307,11 +13200,11 @@ snapshots: transitivePeerDependencies: - aws-crt - "@aws-sdk/client-sts@3.574.0(@aws-sdk/client-sso-oidc@3.574.0)": + "@aws-sdk/client-sts@3.574.0": dependencies: "@aws-crypto/sha256-browser": 3.0.0 "@aws-crypto/sha256-js": 3.0.0 - "@aws-sdk/client-sso-oidc": 3.574.0 + "@aws-sdk/client-sso-oidc": 3.574.0(@aws-sdk/client-sts@3.574.0) "@aws-sdk/core": 3.572.0 "@aws-sdk/credential-provider-node": 3.572.0(@aws-sdk/client-sso-oidc@3.574.0)(@aws-sdk/client-sts@3.574.0) "@aws-sdk/middleware-host-header": 3.567.0 @@ -13350,7 +13243,6 @@ snapshots: "@smithy/util-utf8": 2.3.0 tslib: 2.6.2 transitivePeerDependencies: - - "@aws-sdk/client-sso-oidc" - aws-crt "@aws-sdk/core@3.572.0": @@ -13384,7 +13276,7 @@ snapshots: "@aws-sdk/credential-provider-ini@3.572.0(@aws-sdk/client-sso-oidc@3.574.0)(@aws-sdk/client-sts@3.574.0)": dependencies: - "@aws-sdk/client-sts": 3.574.0(@aws-sdk/client-sso-oidc@3.574.0) + "@aws-sdk/client-sts": 3.574.0 "@aws-sdk/credential-provider-env": 3.568.0 "@aws-sdk/credential-provider-process": 3.572.0 "@aws-sdk/credential-provider-sso": 3.572.0(@aws-sdk/client-sso-oidc@3.574.0) @@ -13441,7 +13333,7 @@ snapshots: "@aws-sdk/credential-provider-web-identity@3.568.0(@aws-sdk/client-sts@3.574.0)": dependencies: - "@aws-sdk/client-sts": 3.574.0(@aws-sdk/client-sso-oidc@3.574.0) + "@aws-sdk/client-sts": 3.574.0 "@aws-sdk/types": 3.567.0 "@smithy/property-provider": 2.2.0 "@smithy/types": 2.12.0 @@ -13557,7 +13449,7 @@ snapshots: "@aws-sdk/token-providers@3.572.0(@aws-sdk/client-sso-oidc@3.574.0)": dependencies: - "@aws-sdk/client-sso-oidc": 3.574.0 + "@aws-sdk/client-sso-oidc": 3.574.0(@aws-sdk/client-sts@3.574.0) "@aws-sdk/types": 3.567.0 "@smithy/property-provider": 2.2.0 "@smithy/shared-ini-file-loader": 2.4.0 @@ -13614,7 +13506,7 @@ snapshots: "@babel/code-frame@7.24.2": dependencies: "@babel/highlight": 7.24.5 - picocolors: 1.0.0 + picocolors: 1.0.1 "@babel/compat-data@7.24.4": {} @@ -13706,7 +13598,7 @@ snapshots: "@babel/helper-validator-identifier": 7.24.5 chalk: 2.4.2 js-tokens: 4.0.0 - picocolors: 1.0.0 + picocolors: 1.0.1 "@babel/parser@7.24.5": dependencies: @@ -14489,8 +14381,6 @@ snapshots: "@next/env@14.2.3": {} - "@next/env@14.2.4": {} - "@next/eslint-plugin-next@13.5.6": dependencies: glob: 7.1.7 @@ -14517,60 +14407,33 @@ snapshots: "@next/swc-darwin-arm64@14.2.10": optional: true - "@next/swc-darwin-arm64@14.2.4": - optional: true - "@next/swc-darwin-x64@14.2.10": optional: true - "@next/swc-darwin-x64@14.2.4": - optional: true - "@next/swc-linux-arm64-gnu@14.2.10": optional: true - "@next/swc-linux-arm64-gnu@14.2.4": - optional: true - "@next/swc-linux-arm64-musl@14.2.10": optional: true - "@next/swc-linux-arm64-musl@14.2.4": - optional: true - "@next/swc-linux-x64-gnu@14.2.10": optional: true - "@next/swc-linux-x64-gnu@14.2.4": - optional: true - "@next/swc-linux-x64-musl@14.2.10": optional: true - "@next/swc-linux-x64-musl@14.2.4": - optional: true - "@next/swc-win32-arm64-msvc@14.2.10": optional: true - "@next/swc-win32-arm64-msvc@14.2.4": - optional: true - "@next/swc-win32-ia32-msvc@14.2.10": optional: true - "@next/swc-win32-ia32-msvc@14.2.4": - optional: true - "@next/swc-win32-x64-msvc@14.2.10": optional: true - "@next/swc-win32-x64-msvc@14.2.4": - optional: true - "@next/third-parties@14.2.3(next@14.2.10(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(react@18.3.1)": dependencies: - next: 14.2.10(react-dom@18.3.1(react@18.3.1))(react@18.3.1) + next: 14.2.10(@babel/core@7.24.5)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) react: 18.3.1 third-party-capital: 1.0.20 @@ -15518,30 +15381,7 @@ snapshots: "@sentry/utils": 7.114.0 localforage: 1.10.0 - "@sentry/nextjs@7.114.0(next@14.2.10(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(react@18.3.1)(webpack@5.93.0)": - dependencies: - "@rollup/plugin-commonjs": 24.0.0(rollup@2.78.0) - "@sentry/core": 7.114.0 - "@sentry/integrations": 7.114.0 - "@sentry/node": 7.114.0 - "@sentry/react": 7.114.0(react@18.3.1) - "@sentry/types": 7.114.0 - "@sentry/utils": 7.114.0 - "@sentry/vercel-edge": 7.114.0 - "@sentry/webpack-plugin": 1.21.0 - chalk: 3.0.0 - next: 14.2.10(react-dom@18.3.1(react@18.3.1))(react@18.3.1) - react: 18.3.1 - resolve: 1.22.8 - rollup: 2.78.0 - stacktrace-parser: 0.1.10 - optionalDependencies: - webpack: 5.93.0 - transitivePeerDependencies: - - encoding - - supports-color - - "@sentry/nextjs@7.114.0(next@14.2.4(@babel/core@7.24.5)(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(react@18.3.1)(webpack@5.93.0)": + "@sentry/nextjs@7.114.0(next@14.2.10(@babel/core@7.24.5)(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(react@18.3.1)(webpack@5.93.0)": dependencies: "@rollup/plugin-commonjs": 24.0.0(rollup@2.78.0) "@sentry/core": 7.114.0 @@ -15553,7 +15393,7 @@ snapshots: "@sentry/vercel-edge": 7.114.0 "@sentry/webpack-plugin": 1.21.0 chalk: 3.0.0 - next: 14.2.4(@babel/core@7.24.5)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) + next: 14.2.10(@babel/core@7.24.5)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) react: 18.3.1 resolve: 1.22.8 rollup: 2.78.0 @@ -15948,7 +15788,7 @@ snapshots: react-merge-refs: 2.1.1 thumbhash: 0.1.1 optionalDependencies: - next: 14.2.10(react-dom@18.3.1(react@18.3.1))(react@18.3.1) + next: 14.2.10(@babel/core@7.24.5)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) "@splinetool/runtime@1.8.7": dependencies: @@ -17024,7 +16864,7 @@ snapshots: browserslist@4.23.0: dependencies: - caniuse-lite: 1.0.30001617 + caniuse-lite: 1.0.30001643 electron-to-chromium: 1.4.763 node-releases: 2.0.14 update-browserslist-db: 1.0.15(browserslist@4.23.0) @@ -17838,7 +17678,7 @@ snapshots: eslint: 8.57.0 eslint-import-resolver-node: 0.3.9 eslint-import-resolver-typescript: 3.6.1(@typescript-eslint/parser@6.21.0(eslint@8.57.0)(typescript@5.4.5))(eslint-import-resolver-node@0.3.9)(eslint-plugin-import@2.29.1(eslint@8.57.0))(eslint@8.57.0) - eslint-plugin-import: 2.29.1(@typescript-eslint/parser@6.21.0(eslint@8.57.0)(typescript@5.4.5))(eslint-import-resolver-typescript@3.6.1(@typescript-eslint/parser@6.21.0(eslint@8.57.0)(typescript@5.4.5))(eslint-import-resolver-node@0.3.9)(eslint-plugin-import@2.29.1(eslint@8.57.0))(eslint@8.57.0))(eslint@8.57.0) + eslint-plugin-import: 2.29.1(@typescript-eslint/parser@6.21.0(eslint@8.57.0)(typescript@5.4.5))(eslint-import-resolver-typescript@3.6.1)(eslint@8.57.0) eslint-plugin-jsx-a11y: 6.8.0(eslint@8.57.0) eslint-plugin-react: 7.34.1(eslint@8.57.0) eslint-plugin-react-hooks: 4.6.2(eslint@8.57.0) @@ -17856,7 +17696,7 @@ snapshots: eslint: 8.57.0 eslint-import-resolver-node: 0.3.9 eslint-import-resolver-typescript: 3.6.1(@typescript-eslint/parser@6.21.0(eslint@8.57.0)(typescript@5.4.5))(eslint-import-resolver-node@0.3.9)(eslint-plugin-import@2.29.1(eslint@8.57.0))(eslint@8.57.0) - eslint-plugin-import: 2.29.1(@typescript-eslint/parser@6.21.0(eslint@8.57.0)(typescript@5.4.5))(eslint-import-resolver-typescript@3.6.1(@typescript-eslint/parser@6.21.0(eslint@8.57.0)(typescript@5.4.5))(eslint-import-resolver-node@0.3.9)(eslint-plugin-import@2.29.1(eslint@8.57.0))(eslint@8.57.0))(eslint@8.57.0) + eslint-plugin-import: 2.29.1(@typescript-eslint/parser@6.21.0(eslint@8.57.0)(typescript@5.4.5))(eslint-import-resolver-typescript@3.6.1)(eslint@8.57.0) eslint-plugin-jsx-a11y: 6.8.0(eslint@8.57.0) eslint-plugin-react: 7.34.1(eslint@8.57.0) eslint-plugin-react-hooks: 4.6.2(eslint@8.57.0) @@ -17874,7 +17714,7 @@ snapshots: eslint: 8.57.0 eslint-import-resolver-node: 0.3.9 eslint-import-resolver-typescript: 3.6.1(@typescript-eslint/parser@6.21.0(eslint@8.57.0)(typescript@5.4.5))(eslint-import-resolver-node@0.3.9)(eslint-plugin-import@2.29.1(eslint@8.57.0))(eslint@8.57.0) - eslint-plugin-import: 2.29.1(@typescript-eslint/parser@6.21.0(eslint@8.57.0)(typescript@5.4.5))(eslint-import-resolver-typescript@3.6.1(@typescript-eslint/parser@6.21.0(eslint@8.57.0)(typescript@5.4.5))(eslint-import-resolver-node@0.3.9)(eslint-plugin-import@2.29.1(eslint@8.57.0))(eslint@8.57.0))(eslint@8.57.0) + eslint-plugin-import: 2.29.1(@typescript-eslint/parser@6.21.0(eslint@8.57.0)(typescript@5.4.5))(eslint-import-resolver-typescript@3.6.1)(eslint@8.57.0) eslint-plugin-jsx-a11y: 6.8.0(eslint@8.57.0) eslint-plugin-react: 7.34.1(eslint@8.57.0) eslint-plugin-react-hooks: 4.6.2(eslint@8.57.0) @@ -17924,7 +17764,7 @@ snapshots: enhanced-resolve: 5.16.1 eslint: 8.57.0 eslint-module-utils: 2.8.1(@typescript-eslint/parser@6.21.0(eslint@8.57.0)(typescript@5.4.5))(eslint-import-resolver-node@0.3.9)(eslint-import-resolver-typescript@3.6.1(@typescript-eslint/parser@6.21.0(eslint@8.57.0)(typescript@5.4.5))(eslint-import-resolver-node@0.3.9)(eslint-plugin-import@2.29.1(eslint@8.57.0))(eslint@8.57.0))(eslint@8.57.0) - eslint-plugin-import: 2.29.1(@typescript-eslint/parser@6.21.0(eslint@8.57.0)(typescript@5.4.5))(eslint-import-resolver-typescript@3.6.1(@typescript-eslint/parser@6.21.0(eslint@8.57.0)(typescript@5.4.5))(eslint-import-resolver-node@0.3.9)(eslint-plugin-import@2.29.1(eslint@8.57.0))(eslint@8.57.0))(eslint@8.57.0) + eslint-plugin-import: 2.29.1(@typescript-eslint/parser@6.21.0(eslint@8.57.0)(typescript@5.4.5))(eslint-import-resolver-typescript@3.6.1)(eslint@8.57.0) fast-glob: 3.3.2 get-tsconfig: 4.7.5 is-core-module: 2.13.1 @@ -17984,7 +17824,7 @@ snapshots: - eslint-import-resolver-webpack - supports-color - eslint-plugin-import@2.29.1(@typescript-eslint/parser@6.21.0(eslint@8.57.0)(typescript@5.4.5))(eslint-import-resolver-typescript@3.6.1(@typescript-eslint/parser@6.21.0(eslint@8.57.0)(typescript@5.4.5))(eslint-import-resolver-node@0.3.9)(eslint-plugin-import@2.29.1(eslint@8.57.0))(eslint@8.57.0))(eslint@8.57.0): + eslint-plugin-import@2.29.1(@typescript-eslint/parser@6.21.0(eslint@8.57.0)(typescript@5.4.5))(eslint-import-resolver-typescript@3.6.1)(eslint@8.57.0): dependencies: array-includes: 3.1.8 array.prototype.findlastindex: 1.2.5 @@ -20598,7 +20438,7 @@ snapshots: "@panva/hkdf": 1.2.1 cookie: 0.5.0 jose: 4.15.5 - next: 14.2.10(react-dom@18.3.1(react@18.3.1))(react@18.3.1) + next: 14.2.10(@babel/core@7.24.5)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) oauth: 0.9.15 openid-client: 5.6.5 preact: 10.22.1 @@ -20618,21 +20458,15 @@ snapshots: transitivePeerDependencies: - supports-color - next-seo@6.5.0(next@14.2.4(@babel/core@7.24.5)(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(react-dom@18.3.1(react@18.3.1))(react@18.3.1): + next-seo@6.5.0(next@14.2.10(@babel/core@7.24.5)(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(react-dom@18.3.1(react@18.3.1))(react@18.3.1): dependencies: - next: 14.2.4(@babel/core@7.24.5)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) + next: 14.2.10(@babel/core@7.24.5)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) react: 18.3.1 react-dom: 18.3.1(react@18.3.1) - next-themes@0.2.1(next@14.2.10(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(react-dom@18.3.1(react@18.3.1))(react@18.3.1): + next-themes@0.2.1(next@14.2.10(@babel/core@7.24.5)(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(react-dom@18.3.1(react@18.3.1))(react@18.3.1): dependencies: - next: 14.2.10(react-dom@18.3.1(react@18.3.1))(react@18.3.1) - react: 18.3.1 - react-dom: 18.3.1(react@18.3.1) - - next-themes@0.2.1(next@14.2.4(@babel/core@7.24.5)(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(react-dom@18.3.1(react@18.3.1))(react@18.3.1): - dependencies: - next: 14.2.4(@babel/core@7.24.5)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) + next: 14.2.10(@babel/core@7.24.5)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) react: 18.3.1 react-dom: 18.3.1(react@18.3.1) @@ -20649,7 +20483,7 @@ snapshots: chalk: 4.1.2 chokidar: 3.6.0 magicast: 0.3.4 - next: 14.2.10(react-dom@18.3.1(react@18.3.1))(react@18.3.1) + next: 14.2.10(@babel/core@7.24.5)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) react: 18.3.1 react-dom: 18.3.1(react@18.3.1) symlink-dir: 5.2.1 @@ -20662,7 +20496,7 @@ snapshots: - aws-crt - encoding - next@14.2.10(react-dom@18.3.1(react@18.3.1))(react@18.3.1): + next@14.2.10(@babel/core@7.24.5)(react-dom@18.3.1(react@18.3.1))(react@18.3.1): dependencies: "@next/env": 14.2.10 "@swc/helpers": 0.5.5 @@ -20687,32 +20521,7 @@ snapshots: - "@babel/core" - babel-plugin-macros - next@14.2.4(@babel/core@7.24.5)(react-dom@18.3.1(react@18.3.1))(react@18.3.1): - dependencies: - "@next/env": 14.2.4 - "@swc/helpers": 0.5.5 - busboy: 1.6.0 - caniuse-lite: 1.0.30001617 - graceful-fs: 4.2.11 - postcss: 8.4.31 - react: 18.3.1 - react-dom: 18.3.1(react@18.3.1) - styled-jsx: 5.1.1(@babel/core@7.24.5)(react@18.3.1) - optionalDependencies: - "@next/swc-darwin-arm64": 14.2.4 - "@next/swc-darwin-x64": 14.2.4 - "@next/swc-linux-arm64-gnu": 14.2.4 - "@next/swc-linux-arm64-musl": 14.2.4 - "@next/swc-linux-x64-gnu": 14.2.4 - "@next/swc-linux-x64-musl": 14.2.4 - "@next/swc-win32-arm64-msvc": 14.2.4 - "@next/swc-win32-ia32-msvc": 14.2.4 - "@next/swc-win32-x64-msvc": 14.2.4 - transitivePeerDependencies: - - "@babel/core" - - babel-plugin-macros - - nextra-theme-docs@2.13.4(next@14.2.4(@babel/core@7.24.5)(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(nextra@2.13.4(next@14.2.4(@babel/core@7.24.5)(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(react-dom@18.3.1(react@18.3.1))(react@18.3.1): + nextra-theme-docs@2.13.4(next@14.2.10(@babel/core@7.24.5)(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(nextra@2.13.4(next@14.2.10(@babel/core@7.24.5)(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(react-dom@18.3.1(react@18.3.1))(react@18.3.1): dependencies: "@headlessui/react": 1.7.19(react-dom@18.3.1(react@18.3.1))(react@18.3.1) "@popperjs/core": 2.11.8 @@ -20723,16 +20532,16 @@ snapshots: git-url-parse: 13.1.1 intersection-observer: 0.12.2 match-sorter: 6.3.4 - next: 14.2.4(@babel/core@7.24.5)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) - next-seo: 6.5.0(next@14.2.4(@babel/core@7.24.5)(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(react-dom@18.3.1(react@18.3.1))(react@18.3.1) - next-themes: 0.2.1(next@14.2.4(@babel/core@7.24.5)(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(react-dom@18.3.1(react@18.3.1))(react@18.3.1) - nextra: 2.13.4(next@14.2.4(@babel/core@7.24.5)(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(react-dom@18.3.1(react@18.3.1))(react@18.3.1) + next: 14.2.10(@babel/core@7.24.5)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) + next-seo: 6.5.0(next@14.2.10(@babel/core@7.24.5)(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(react-dom@18.3.1(react@18.3.1))(react@18.3.1) + next-themes: 0.2.1(next@14.2.10(@babel/core@7.24.5)(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(react-dom@18.3.1(react@18.3.1))(react@18.3.1) + nextra: 2.13.4(next@14.2.10(@babel/core@7.24.5)(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(react-dom@18.3.1(react@18.3.1))(react@18.3.1) react: 18.3.1 react-dom: 18.3.1(react@18.3.1) scroll-into-view-if-needed: 3.1.0 zod: 3.23.8 - nextra@2.13.4(next@14.2.4(@babel/core@7.24.5)(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(react-dom@18.3.1(react@18.3.1))(react@18.3.1): + nextra@2.13.4(next@14.2.10(@babel/core@7.24.5)(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(react-dom@18.3.1(react@18.3.1))(react@18.3.1): dependencies: "@headlessui/react": 1.7.19(react-dom@18.3.1(react@18.3.1))(react@18.3.1) "@mdx-js/mdx": 2.3.0 @@ -20746,7 +20555,7 @@ snapshots: gray-matter: 4.0.3 katex: 0.16.10 lodash.get: 4.4.2 - next: 14.2.4(@babel/core@7.24.5)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) + next: 14.2.10(@babel/core@7.24.5)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) next-mdx-remote: 4.4.1(react-dom@18.3.1(react@18.3.1))(react@18.3.1) p-limit: 3.1.0 react: 18.3.1 @@ -22344,7 +22153,7 @@ snapshots: dependencies: browserslist: 4.23.0 escalade: 3.1.2 - picocolors: 1.0.0 + picocolors: 1.0.1 update-browserslist-db@1.1.0(browserslist@4.23.2): dependencies: