diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 99d3e017..1fc2ae1c 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -60,7 +60,4 @@ The video segments are stored in your app data directory, under the folder `so.c ### Notes for development on Windows: - - -Required dlls: `avutil`, `avformat`, `avcodec`, `avdevice`. -Put the full version of ffmpeg for the target arch into `target/binaries`. +Requirements: llvm, clang and VCPKG are required for compiling ffmpeg-sys. diff --git a/Cargo.lock b/Cargo.lock index abc0a223..ea66481a 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -960,11 +960,15 @@ dependencies = [ name = "cap-utils" version = "0.1.0" dependencies = [ + "flume 0.11.0", "futures", "nix 0.29.0", + "serde", + "serde_json", "tokio", "uuid", "windows 0.58.0", + "windows-sys 0.52.0", ] [[package]] @@ -1955,6 +1959,7 @@ dependencies = [ "tauri-plugin-notification", "tauri-plugin-oauth", "tauri-plugin-os", + "tauri-plugin-positioner", "tauri-plugin-process", "tauri-plugin-shell", "tauri-plugin-single-instance", @@ -7042,9 +7047,9 @@ dependencies = [ [[package]] name = "tauri-plugin-fs" -version = "2.1.0" +version = "2.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0cdaf6701ee5efc83161cf41004aa5aec4d255c9fb2d2b11fe518fe506acc588" +checksum = "a1a1edf18000f02903a7c2e5997fb89aca455ecbc0acc15c6535afbb883be223" dependencies = [ "anyhow", "dunce", @@ -7065,9 +7070,9 @@ dependencies = [ [[package]] name = "tauri-plugin-global-shortcut" -version = "2.0.1" +version = "2.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2c15fb7f5e4c80a73ce97217dcff27e423f496178cbcb87e13b4efe99eebb550" +checksum = "00f646a09511e8d283267dcdaa08c2ef27c4116bf271d9114849d9ca215606c3" dependencies = [ "global-hotkey", "log", @@ -7075,14 +7080,14 @@ dependencies = [ "serde_json", "tauri", "tauri-plugin", - "thiserror 1.0.63", + "thiserror 2.0.6", ] [[package]] name = "tauri-plugin-http" -version = "2.0.4" +version = "2.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fd6f26c4e715b50f06e3fde65cda1d805dae23f04869a01380c4cf8708dbb296" +checksum = "e62a9bde54d6a0218b63f5a248f02056ad4316ba6ad81dfb9e4f73715df5deb1" dependencies = [ "data-url", "http", @@ -7102,9 +7107,9 @@ dependencies = [ [[package]] name = "tauri-plugin-notification" -version = "2.0.1" +version = "2.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ef492a2d19b6376bb4c9e0c4fab3f3bf8a220ea112d24f35027b737ff55de20c" +checksum = "46ab803095f14ac6521fdb6477210a49e86fed6623c3c97d8e4b2b35e045e922" dependencies = [ "log", "notify-rust", @@ -7114,7 +7119,7 @@ dependencies = [ "serde_repr", "tauri", "tauri-plugin", - "thiserror 1.0.63", + "thiserror 2.0.6", "time", "url", ] @@ -7135,9 +7140,9 @@ dependencies = [ [[package]] name = "tauri-plugin-os" -version = "2.0.1" +version = "2.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fbc5f23a86f37687c7f4fecfdc706b279087bc44f7a46702f7307ff1551ee03a" +checksum = "dda2d571a9baf0664c1f2088db227e3072f9028602fafa885deade7547c3b738" dependencies = [ "gethostname 0.5.0", "log", @@ -7148,7 +7153,22 @@ dependencies = [ "sys-locale", "tauri", "tauri-plugin", - "thiserror 1.0.63", + "thiserror 2.0.6", +] + +[[package]] +name = "tauri-plugin-positioner" +version = "2.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8c95b371d489bee3d1be5e5bd1538080ad408317fcc2d8546d24b290249f7bb5" +dependencies = [ + "log", + "serde", + "serde_json", + "serde_repr", + "tauri", + "tauri-plugin", + "thiserror 2.0.6", ] [[package]] @@ -7163,9 +7183,9 @@ dependencies = [ [[package]] name = "tauri-plugin-shell" -version = "2.0.2" +version = "2.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0ad7880c5586b6b2104be451e3d7fc0f3800c84bda69e9ba81c828f87cb34267" +checksum = "bb2c50a63e60fb8925956cc5b7569f4b750ac197a4d39f13b8dd46ea8e2bad79" dependencies = [ "encoding_rs", "log", @@ -7178,7 +7198,7 @@ dependencies = [ "shared_child", "tauri", "tauri-plugin", - "thiserror 1.0.63", + "thiserror 2.0.6", "tokio", ] @@ -7199,25 +7219,25 @@ dependencies = [ [[package]] name = "tauri-plugin-store" -version = "2.1.0" +version = "2.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e9a580be53f04bb62422d239aa798e88522877f58a0d4a0e745f030055a51bb4" +checksum = "1c0c08fae6995909f5e9a0da6038273b750221319f2c0f3b526d6de1cde21505" dependencies = [ "dunce", - "log", "serde", "serde_json", "tauri", "tauri-plugin", - "thiserror 1.0.63", + "thiserror 2.0.6", "tokio", + "tracing", ] [[package]] name = "tauri-plugin-updater" -version = "2.1.0" +version = "2.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "50ba9adaede60b0df5e0764692c6ac176eb133aade95d326bddeb968ad793320" +checksum = "b7351014c140906bcfff59d96e04b1170c8f602557f40eb37f7de356d4e7067b" dependencies = [ "base64 0.22.1", "dirs", @@ -7245,9 +7265,9 @@ dependencies = [ [[package]] name = "tauri-plugin-window-state" -version = "2.0.2" +version = "2.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "683c8764751fbbcebf3a594bcee24cf84c62773fa0080d1b40fc80698472421e" +checksum = "234dd891cc7960fa28f93ea911f3e0d9ce8375ebf9ff303831bdd7a3443d5714" dependencies = [ "bitflags 2.6.0", "log", @@ -7255,7 +7275,7 @@ dependencies = [ "serde_json", "tauri", "tauri-plugin", - "thiserror 1.0.63", + "thiserror 2.0.6", ] [[package]] diff --git a/apps/desktop/package.json b/apps/desktop/package.json index e6a708a1..677ba076 100644 --- a/apps/desktop/package.json +++ b/apps/desktop/package.json @@ -2,7 +2,7 @@ "name": "@cap/desktop", "type": "module", "scripts": { - "dev": "RUST_BACKTRACE=1 dotenv -e ../../.env -- pnpm run preparescript && tauri dev", + "dev": "cross-env RUST_BACKTRACE=1 dotenv -e ../../.env -- pnpm run preparescript && tauri dev", "build:tauri": "dotenv -e ../../.env -- pnpm run preparescript && tauri build", "preparescript": "node scripts/prepare.js", "localdev": "dotenv -e ../../.env -- vinxi dev --port 3001", @@ -64,6 +64,7 @@ "@tauri-apps/cli": ">=2.1.0", "@total-typescript/ts-reset": "^0.6.1", "@types/dom-webcodecs": "^0.1.11", + "cross-env": "^7.0.3", "typescript": "^5.7.2", "vite": "^5.4.3", "vite-tsconfig-paths": "^5.0.1" diff --git a/apps/desktop/src-tauri/Cargo.toml b/apps/desktop/src-tauri/Cargo.toml index 8f7fc3ff..a06751cc 100644 --- a/apps/desktop/src-tauri/Cargo.toml +++ b/apps/desktop/src-tauri/Cargo.toml @@ -26,18 +26,19 @@ tauri = { workspace = true, features = [ ] } tauri-specta = { version = "=2.0.0-rc.20", features = ["derive", "typescript"] } tauri-plugin-dialog = "2.0.0" -tauri-plugin-fs = "2.0.0-rc.0" -tauri-plugin-global-shortcut = "2.0.1" -tauri-plugin-http = "2.0.4" -tauri-plugin-notification = "2.0.1" -tauri-plugin-os = "2.0.0" +tauri-plugin-fs = "2.2.0" +tauri-plugin-global-shortcut = "2.1.0" +tauri-plugin-http = "2.1.0" +tauri-plugin-notification = "2.1.0" +tauri-plugin-os = "2.1.0" tauri-plugin-process = "2.0.1" -tauri-plugin-shell = "2.0.0" +tauri-plugin-shell = "2.1.0" tauri-plugin-single-instance = "2.0.1" -tauri-plugin-store = "2.0.0" -tauri-plugin-updater = "2.1.0" +tauri-plugin-store = "2.2.0" +tauri-plugin-updater = "2.2.0" tauri-plugin-oauth = { git = "https://github.com/FabianLars/tauri-plugin-oauth", branch = "v2" } -tauri-plugin-window-state = "2.0.2" +tauri-plugin-window-state = "2.2.0" +tauri-plugin-positioner = "2.2.0" serde = { version = "1", features = ["derive"] } serde_json = "1" diff --git a/apps/desktop/src-tauri/src/lib.rs b/apps/desktop/src-tauri/src/lib.rs index c2a8afae..149e8f33 100644 --- a/apps/desktop/src-tauri/src/lib.rs +++ b/apps/desktop/src-tauri/src/lib.rs @@ -1896,21 +1896,8 @@ pub async fn run() { #[cfg(target_os = "macos")] { - builder = builder.plugin(tauri_nspanel::init()); - } - - builder - .plugin(tauri_plugin_shell::init()) - .plugin(tauri_plugin_dialog::init()) - .plugin(tauri_plugin_store::Builder::new().build()) - .plugin(tauri_plugin_os::init()) - .plugin(tauri_plugin_process::init()) - .plugin(tauri_plugin_oauth::init()) - .plugin(tauri_plugin_http::init()) - .plugin(tauri_plugin_updater::Builder::new().build()) - .plugin(tauri_plugin_notification::init()) - .plugin(tauri_plugin_deep_link::init()) - .plugin( + builder = builder.plugin(tauri_nspanel::init()).plugin( + // TODO(Ilya): Also enable for Windows when Tao is updated to `0.31.0` tauri_plugin_window_state::Builder::new() .with_state_flags({ use tauri_plugin_window_state::StateFlags; @@ -1930,8 +1917,21 @@ pub async fn run() { _ => label, }) .build(), - ) + ); + } + + builder + .plugin(tauri_plugin_shell::init()) + .plugin(tauri_plugin_dialog::init()) + .plugin(tauri_plugin_store::Builder::new().build()) + .plugin(tauri_plugin_os::init()) + .plugin(tauri_plugin_process::init()) + .plugin(tauri_plugin_oauth::init()) + .plugin(tauri_plugin_http::init()) + .plugin(tauri_plugin_updater::Builder::new().build()) + .plugin(tauri_plugin_notification::init()) .plugin(flags::plugin::init()) + .plugin(tauri_plugin_deep_link::init()) .invoke_handler({ let handler = specta_builder.invoke_handler(); @@ -2091,25 +2091,27 @@ pub async fn run() { match event { WindowEvent::Destroyed => { - match CapWindowId::from_str(label).unwrap() { - CapWindowId::Main => { - if let Some(w) = CapWindowId::Camera.get(app) { - w.close().ok(); + if let Ok(window_id) = CapWindowId::from_str(label) { + match window_id { + CapWindowId::Main => { + if let Some(w) = CapWindowId::Camera.get(app) { + w.close().ok(); + } } - } - CapWindowId::Editor { project_id } => { - let app_handle = app.clone(); - tokio::spawn(async move { - let _ = remove_editor_instance(&app_handle, project_id).await; - tokio::task::yield_now().await; - }); - } - CapWindowId::Settings | CapWindowId::Upgrade => { - // Don't quit the app when settings or upgrade window is closed - return; - } - _ => {} - }; + CapWindowId::Editor { project_id } => { + let app_handle = app.clone(); + tokio::spawn(async move { + let _ = remove_editor_instance(&app_handle, project_id).await; + tokio::task::yield_now().await; + }); + } + CapWindowId::Settings | CapWindowId::Upgrade => { + // Don't quit the app when settings or upgrade window is closed + return; + } + _ => {} + }; + } if let Some(settings) = GeneralSettingsStore::get(app).unwrap_or(None) { if settings.hide_dock_icon @@ -2123,11 +2125,13 @@ pub async fn run() { } } } + #[cfg(target_os = "macos")] WindowEvent::Focused(focused) if *focused => { - if CapWindowId::from_str(label).unwrap().activates_dock() { - #[cfg(target_os = "macos")] - app.set_activation_policy(tauri::ActivationPolicy::Regular) - .ok(); + if let Ok(window_id) = CapWindowId::from_str(label) { + if window_id.activates_dock() { + app.set_activation_policy(tauri::ActivationPolicy::Regular) + .ok(); + } } } _ => {} diff --git a/apps/desktop/src-tauri/src/windows.rs b/apps/desktop/src-tauri/src/windows.rs index d4e977f3..ca0e0264 100644 --- a/apps/desktop/src-tauri/src/windows.rs +++ b/apps/desktop/src-tauri/src/windows.rs @@ -1,4 +1,5 @@ #![allow(unused_mut)] +#![allow(unused_imports)] use crate::{fake_window, general_settings::AppTheme}; use cap_flags::FLAGS; @@ -9,8 +10,12 @@ use tauri::{ AppHandle, LogicalPosition, Manager, WebviewUrl, WebviewWindow, WebviewWindowBuilder, Wry, }; +#[cfg(target_os = "macos")] const DEFAULT_TRAFFIC_LIGHTS_INSET: LogicalPosition = LogicalPosition::new(12.0, 12.0); +#[cfg(target_os = "windows")] +const WIN_WSCAPTION_WSTHICKFRAME_LOGICAL_SIZE: tauri::LogicalSize = tauri::LogicalSize::new(12.0, 35.0); + #[derive(Clone)] pub enum CapWindowId { // Contains onboarding + permissions @@ -90,6 +95,7 @@ impl CapWindowId { app.get_webview_window(&label) } + #[cfg(target_os = "macos")] pub fn traffic_lights_position(&self) -> Option>> { match self { Self::Editor { .. } => Some(Some(LogicalPosition::new(20.0, 40.0))), @@ -99,10 +105,12 @@ impl CapWindowId { _ => Some(None), } } + pub fn min_size(&self) -> Option<(f64, f64)> { Some(match self { Self::Setup => (600.0, 600.0), Self::Main => (300.0, 360.0), + Self::Editor { .. } => (900.0, 800.0), Self::Settings => (600.0, 450.0), Self::Camera => (460.0, 920.0), _ => return None, @@ -151,6 +159,7 @@ impl ShowCapWindow { .resizable(false) .maximized(false) .maximizable(false) + .center() .build()?, Self::Settings { page } => self .window_builder( @@ -159,11 +168,13 @@ impl ShowCapWindow { ) .resizable(true) .maximized(false) + .center() .build()?, Self::Editor { project_id } => self .window_builder(app, format!("/editor?id={project_id}")) .inner_size(1150.0, 800.0) .maximizable(true) + .center() .build()?, Self::Upgrade => self .window_builder(app, "/upgrade") @@ -173,6 +184,7 @@ impl ShowCapWindow { .always_on_top(true) .maximized(false) .transparent(true) + .center() .build()?, Self::Camera { ws_port } => { const WINDOW_SIZE: f64 = 230.0 * 2.0; @@ -242,7 +254,12 @@ impl ShowCapWindow { if FLAGS.pause_resume { width += 32.0; } - let height = 40.0; + let mut height = 40.0; + #[cfg(target_os = "windows")] + { + width -= WIN_WSCAPTION_WSTHICKFRAME_LOGICAL_SIZE.width; + height -= WIN_WSCAPTION_WSTHICKFRAME_LOGICAL_SIZE.height; + } self.window_builder(app, "/in-progress-recording") .maximized(false) @@ -318,6 +335,44 @@ impl ShowCapWindow { window.hide().ok(); + // TODO(Ilya): Remove once Tao is updated to `0.31.0` + #[cfg(target_os = "windows")] + { + use tauri_plugin_positioner::{Position, WindowExt}; + + if matches!( + self, + Self::Setup + | Self::Main + | Self::Editor { .. } + | Self::Settings { .. } + | Self::Upgrade + ) { + let _ = window.move_window(Position::Center); + } + + if matches!(self, Self::InProgressRecording { .. }) { + let _ = window.move_window(Position::BottomCenter); + + if let Ok(outer_size) = window.outer_size() { + let screen_position = monitor.position(); + let window_size = tauri::PhysicalSize:: { + width: outer_size.width as i32, + height: outer_size.height as i32, + }; + let screen_size = tauri::PhysicalSize:: { + width: monitor.size().width as i32, + height: monitor.size().height as i32, + }; + + let _ = window.set_position(tauri::PhysicalPosition { + x: screen_position.x + ((screen_size.width / 2) - (window_size.width / 2)), + y: screen_size.height - (window_size.height - screen_position.y) - 120, + }); + } + } + } + #[cfg(target_os = "macos")] if let Some(position) = id.traffic_lights_position() { add_traffic_lights(&window, position); @@ -340,9 +395,32 @@ impl ShowCapWindow { .shadow(true); if let Some(min) = id.min_size() { + // TODO(Ilya): Remove once Tao is updated to `0.31.0` + // currently, undecorated windows with shadows get the invisible bounds of the titlebar and window frame added to the inner size + #[cfg(target_os = "windows")] + let size = if matches!( + self, + Self::Setup + | Self::Main + | Self::Editor { .. } + | Self::Settings { .. } + | Self::InProgressRecording { .. } + | Self::Upgrade + ) { + ( + min.0 - WIN_WSCAPTION_WSTHICKFRAME_LOGICAL_SIZE.width, + min.1 - WIN_WSCAPTION_WSTHICKFRAME_LOGICAL_SIZE.height, + ) + } else { + min + }; + + #[cfg(not(target_os = "windows"))] + let size = min; + builder = builder - .inner_size(min.0, min.1) - .min_inner_size(min.0, min.1); + .inner_size(size.0, size.1) + .min_inner_size(size.0, size.1); } #[cfg(target_os = "macos")] diff --git a/apps/desktop/src/components/titlebar/Titlebar.tsx b/apps/desktop/src/components/titlebar/Titlebar.tsx index 16019842..e26e1a8a 100644 --- a/apps/desktop/src/components/titlebar/Titlebar.tsx +++ b/apps/desktop/src/components/titlebar/Titlebar.tsx @@ -14,7 +14,7 @@ export default function Titlebar() { return (
) { local.class, focused() ? "*:text-black-transparent-80" : "*:text-black-transparent-40" )} - style={{ - "font-family": "Segoe Fluent Icons', 'Segoe MDL2 Assets" - }} {...otherProps} > -
-
- - + batch(() => { + setTitlebar("border", false); + setTitlebar("height", "4rem"); + setTitlebar("transparent", true); + setTitlebar( + "items", +
+
+
+ + +
-
- ); + ); + }); return ( <> diff --git a/apps/desktop/src/routes/in-progress-recording.tsx b/apps/desktop/src/routes/in-progress-recording.tsx index d18f878c..07b0627b 100644 --- a/apps/desktop/src/routes/in-progress-recording.tsx +++ b/apps/desktop/src/routes/in-progress-recording.tsx @@ -172,7 +172,7 @@ export default function () { class="non-styled-move cursor-move flex items-center justify-center p-[0.25rem] border-l border-gray-400 dark:border-gray-200 hover:cursor-move" data-tauri-drag-region > - + ); diff --git a/crates/media/src/feeds/audio_input.rs b/crates/media/src/feeds/audio_input.rs index 49b53200..83fb834a 100644 --- a/crates/media/src/feeds/audio_input.rs +++ b/crates/media/src/feeds/audio_input.rs @@ -1,8 +1,8 @@ -use cpal::traits::{DeviceTrait, HostTrait}; +use cpal::traits::{DeviceTrait, HostTrait, StreamTrait}; use cpal::{Device, InputCallbackInfo, SampleFormat, StreamConfig, SupportedStreamConfig}; use flume::{Receiver, Sender, TrySendError}; use indexmap::IndexMap; -use tracing::warn; +use tracing::{warn, error, info, debug}; use crate::{ data::{ffmpeg_sample_format_for, AudioInfo}, @@ -55,37 +55,52 @@ impl AudioInputFeed { } pub async fn init(selected_input: &str) -> Result { + info!("Initializing audio input feed with device: {}", selected_input); + let (device, config) = Self::list_devices() .swap_remove_entry(selected_input) .map(|(device_name, (device, config))| { - println!("Using audio device: {}", device_name); + info!("Using audio device: {} with config: {:?}", device_name, config); (device, config) }) - .unwrap(); + .ok_or_else(|| { + error!("Failed to find audio device: {}", selected_input); + MediaError::DeviceUnreachable(selected_input.to_string()) + })?; - let audio_info = AudioInfo::from_stream_config(&config)?; + let audio_info = AudioInfo::from_stream_config(&config).map_err(|e| { + error!("Failed to create audio info from stream config: {}", e); + e + })?; + + debug!("Created audio info: {:?}", audio_info); let (control_tx, control_rx) = flume::bounded(1); std::thread::spawn(|| start_capturing(device, config, control_rx)); + info!("Started audio capture thread"); Ok(Self { control_tx, audio_info, - // rx: samples_rx, }) } pub fn list_devices() -> AudioInputDeviceMap { + info!("Listing available audio input devices"); let host = cpal::default_host(); let mut device_map = IndexMap::new(); let get_usable_device = |device: Device| { device .supported_input_configs() - .map_err(|error| eprintln!("Error: {error}")) + .map_err(|error| { + error!("Error getting supported input configs for device: {}", error); + error + }) .ok() .and_then(|configs| { let mut configs = configs.collect::>(); + debug!("Found {} supported configs", configs.len()); configs.sort_by(|a, b| { b.sample_format() .sample_size() @@ -100,31 +115,33 @@ impl AudioInputFeed { .find(|c| ffmpeg_sample_format_for(c.sample_format()).is_some()) }) .and_then(|config| { - device - .name() - .ok() - .map(|name| (name, device, config.with_max_sample_rate())) + device.name().ok().map(|name| { + debug!("Found usable device: {} with config: {:?}", name, config); + (name, device, config.with_max_sample_rate()) + }) }) }; - if let Some((name, device, config)) = - host.default_input_device().and_then(get_usable_device) - { + if let Some((name, device, config)) = host.default_input_device().and_then(get_usable_device) { + info!("Found default input device: {}", name); device_map.insert(name, (device, config)); + } else { + warn!("No default input device found or it's not usable"); } match host.input_devices() { Ok(devices) => { for (name, device, config) in devices.filter_map(get_usable_device) { + debug!("Found additional device: {}", name); device_map.entry(name).or_insert((device, config)); } } Err(error) => { - eprintln!("Could not access audio input devices"); - eprintln!("{error}"); + error!("Could not access audio input devices: {}", error); } } + info!("Found {} usable audio input devices", device_map.len()); device_map } @@ -179,43 +196,64 @@ fn start_capturing( mut config: SupportedStreamConfig, control: Receiver, ) { + info!("Starting audio capture with device: {:?}, config: {:?}", device.name(), config); let mut senders: Vec = vec![]; loop { let (tx, rx) = flume::bounded(4); + info!("Building input stream with config: {:?}", config); let stream_config: StreamConfig = config.clone().into(); - let stream = device + let stream = match device .build_input_stream_raw( &stream_config, config.sample_format(), move |data, info| { - tx.send(AudioInputSamples { + if let Err(e) = tx.send(AudioInputSamples { data: data.bytes().to_vec(), format: data.sample_format(), info: info.clone(), - }) - .ok(); + }) { + error!("Failed to send audio samples: {}", e); + } + }, + |e| { + error!("Error in audio input stream: {}", e); }, - |_e| {}, None, - ) - .map_err(|error| { - eprintln!("Error while preparing audio capture: {error}"); - MediaError::TaskLaunch("Failed to start audio capture".into()) - }); + ) { + Ok(stream) => { + info!("Successfully built audio input stream"); + stream + } + Err(err) => { + error!("Failed to build audio input stream: {}", err); + // Sleep briefly to avoid tight error loop + std::thread::sleep(std::time::Duration::from_secs(1)); + continue; + } + }; + + // Try to play the stream + if let Err(e) = stream.play() { + error!("Failed to start audio stream playback: {}", e); + continue; + } + info!("Audio stream playback started"); loop { match control.try_recv() { Ok(AudioInputControl::Switch(name, response)) => { + info!("Switching audio device to: {}", name); // list_devices hangs if the stream isn't dropped drop(stream); let Some(items) = AudioInputFeed::list_devices().swap_remove_entry(&name).map( |(device_name, (device, config))| { - println!("Using audio device: {}", device_name); + info!("Switching to audio device: {} with config: {:?}", device_name, config); (device, config) }, ) else { + error!("Failed to find audio device: {}", name); response .send(Err(MediaError::DeviceUnreachable(name))) .unwrap(); @@ -229,13 +267,15 @@ fn start_capturing( break; } Ok(AudioInputControl::Shutdown) => { + info!("Received shutdown signal for audio capture"); return; } Ok(AudioInputControl::AttachSender(sender)) => { + info!("New audio sender attached"); senders.push(sender); } Err(flume::TryRecvError::Disconnected) => { - println!("Control receiver is unreachable! Shutting down"); + warn!("Control receiver is unreachable! Shutting down audio capture"); return; } Err(flume::TryRecvError::Empty) => { @@ -248,19 +288,22 @@ fn start_capturing( let mut to_remove = vec![]; for (i, sender) in senders.iter().enumerate() { if let Err(TrySendError::Disconnected(_)) = sender.try_send(data.clone()) { + warn!("Audio sender {} disconnected, will be removed", i); to_remove.push(i); }; } - for i in to_remove.into_iter().rev() { - senders.swap_remove(i); + if !to_remove.is_empty() { + debug!("Removing {} disconnected audio senders", to_remove.len()); + for i in to_remove.into_iter().rev() { + senders.swap_remove(i); + } } } Err(error) => { - warn!("Failed to capture audio sampels: {:?}", error); - // Optionally, add a small delay to avoid busy-waiting - std::thread::sleep(std::time::Duration::from_millis(10)); - continue; + error!("Failed to capture audio samples: {:?}", error); + // Break inner loop to recreate the stream + break; } } } diff --git a/crates/utils/Cargo.toml b/crates/utils/Cargo.toml index 668d7971..520963df 100644 --- a/crates/utils/Cargo.toml +++ b/crates/utils/Cargo.toml @@ -17,8 +17,12 @@ windows = { version = "0.58.0", features = [ "Win32_System_Pipes", "Win32_System_Diagnostics_Debug", ] } +windows-sys = "0.52.0" [dependencies] futures = "0.3.31" -tokio = { workspace = true, features = ["net"] } +tokio = { workspace = true, features = ["net", "io-util"] } uuid = "1.11.0" +serde = { version = "1.0", features = ["derive"] } +serde_json = "1.0" +flume = "0.11.0" diff --git a/crates/utils/src/lib.rs b/crates/utils/src/lib.rs index 533ed800..79658364 100644 --- a/crates/utils/src/lib.rs +++ b/crates/utils/src/lib.rs @@ -1,6 +1,6 @@ -use futures::FutureExt; -use std::{ffi::OsString, fs::OpenOptions, io::Write, path::PathBuf}; -// use tokio::{fs::OpenOptions, io::AsyncWriteExt}; +use std::{ffi::OsString, path::PathBuf}; +use tokio::io::AsyncWriteExt; +use tokio::sync::mpsc::Receiver; #[cfg(windows)] pub fn get_last_win32_error_formatted() -> String { @@ -42,75 +42,78 @@ fn create_named_pipe(path: &std::path::Path) -> Result<(), Box( - mut rx: tokio::sync::mpsc::Receiver, - unix_path: PathBuf, - get_bytes: impl FnMut(&T) -> Option<&[u8]> + Clone + Send + 'static, -) -> OsString { - #[cfg(unix)] +pub fn create_channel_named_pipe( + mut rx: Receiver, + pipe_path: PathBuf, + mut chunk_fn: F, +) -> OsString +where + T: Send + 'static, + F: FnMut(&T) -> Option<&[u8]> + Send + 'static, +{ + #[cfg(windows)] { - create_named_pipe(&unix_path).unwrap(); - - let path = unix_path.clone(); - tokio::spawn( - async move { - let mut file = OpenOptions::new() - .write(true) - .create(false) - .truncate(true) - .open(&path) - // .await - .unwrap(); - println!("video pipe opened"); - - while let Some(bytes) = rx.recv().await { - let mut get_bytes = get_bytes.clone(); - - while let Some(bytes) = get_bytes(&bytes) { - file.write_all(&bytes).unwrap(); + // Build proper Windows named pipe path, e.g. \\.\pipe\my_pipe_name + // Use the final filename from `pipe_path` to avoid conflicts + let filename = pipe_path + .file_name() + .unwrap_or_else(|| std::ffi::OsStr::new("cap-default-pipe")); + let pipe_name = format!(r"\\.\pipe\{}", filename.to_string_lossy()); + let os_pipe_name = OsString::from(&pipe_name); + + tokio::spawn(async move { + let mut server = tokio::net::windows::named_pipe::ServerOptions::new() + .first_pipe_instance(true) + .create(&pipe_name) + .expect("Failed to create named pipe"); + + // For each message from rx, repeatedly call chunk_fn until None is returned + while let Some(msg) = rx.recv().await { + loop { + if let Some(bytes) = chunk_fn(&msg) { + if let Err(e) = server.write_all(bytes).await { + eprintln!("Error writing to named pipe: {e}"); + break; + } + } else { + break; } } - - println!("done writing to video pipe"); - Ok::<(), std::io::Error>(()) } - .then(|result| async { - if let Err(e) = result { - eprintln!("error writing to video pipe: {}", e); - } - }), - ); + }); - unix_path.into_os_string() + return os_pipe_name; } - #[cfg(windows)] + #[cfg(unix)] { - use tokio::io::AsyncWriteExt; - use tokio::net::windows::named_pipe::ServerOptions; - - let uuid = uuid::Uuid::new_v4(); - let pipe_name = format!(r#"\\.\pipe\{uuid}"#); - - let mut server = ServerOptions::new() - .first_pipe_instance(true) - .create(&pipe_name) - .unwrap(); - - tokio::spawn({ - async move { - println!("video pipe opened"); - - server.connect().await.unwrap(); - - while let Some(bytes) = rx.recv().await { - server.write_all(&bytes).await.unwrap(); + use nix::sys::stat; + let os_pipe_name = pipe_path.clone().into_os_string(); + + let _ = std::fs::remove_file(&pipe_path); + // Make FIFO if not existing + stat::mkfifo(&pipe_path, stat::Mode::S_IRWXU) + .expect("Failed to create a Unix FIFO with mkfifo()"); + + tokio::spawn(async move { + let mut file = tokio::fs::File::create(&pipe_path) + .await + .expect("Failed to open FIFO for writing"); + + while let Some(msg) = rx.recv().await { + loop { + if let Some(bytes) = chunk_fn(&msg) { + if let Err(e) = file.write_all(bytes).await { + eprintln!("Error writing to FIFO: {e}"); + break; + } + } else { + break; + } } - - println!("done writing to video pipe"); } }); - pipe_name.into() + return os_pipe_name; } } diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 1cd8935c..393d98cc 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -18,7 +18,7 @@ importers: version: 1.13.4(@types/node@20.16.9)(typescript@5.7.2) dotenv-cli: specifier: latest - version: 7.4.4 + version: 8.0.0 eslint: specifier: ^7.32.0 version: 7.32.0 @@ -191,6 +191,9 @@ importers: '@types/dom-webcodecs': specifier: ^0.1.11 version: 0.1.11 + cross-env: + specifier: ^7.0.3 + version: 7.0.3 typescript: specifier: ^5.7.2 version: 5.7.2 @@ -415,7 +418,7 @@ importers: version: 8.57.1 eslint-config-airbnb-typescript: specifier: ^18.0.0 - version: 18.0.0(@typescript-eslint/eslint-plugin@7.18.0(@typescript-eslint/parser@7.18.0(eslint@8.57.1)(typescript@5.7.2))(eslint@8.57.1)(typescript@5.7.2))(@typescript-eslint/parser@7.18.0(eslint@8.57.1)(typescript@5.7.2))(eslint-plugin-import@2.30.0)(eslint@8.57.1) + version: 18.0.0(@typescript-eslint/eslint-plugin@7.18.0(@typescript-eslint/parser@7.18.0(eslint@8.57.1)(typescript@5.7.2))(eslint@8.57.1)(typescript@5.7.2))(@typescript-eslint/parser@7.18.0(eslint@8.57.1)(typescript@5.7.2))(eslint-plugin-import@2.30.0(@typescript-eslint/parser@7.18.0(eslint@8.57.1)(typescript@5.7.2))(eslint-import-resolver-typescript@3.6.3)(eslint@8.57.1))(eslint@8.57.1) eslint-import-resolver-typescript: specifier: ^3.6.1 version: 3.6.3(@typescript-eslint/parser@7.18.0(eslint@8.57.1)(typescript@5.7.2))(eslint-plugin-import@2.30.0)(eslint@8.57.1) @@ -754,10 +757,10 @@ importers: version: 18.3.9 '@types/react-dom': specifier: latest - version: 19.0.0 + version: 19.0.2(@types/react@18.3.9) dotenv-cli: specifier: latest - version: 7.4.4 + version: 8.0.0 drizzle-kit: specifier: ^0.20.12 version: 0.20.18 @@ -792,25 +795,25 @@ importers: version: 0.9.0(tailwindcss@3.4.13(ts-node@10.9.2(@types/node@20.16.9)(typescript@5.7.2))) '@radix-ui/react-dialog': specifier: ^1.0.5 - version: 1.1.1(@types/react-dom@19.0.0)(@types/react@18.3.9)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) + version: 1.1.1(@types/react-dom@19.0.2(@types/react@18.3.9))(@types/react@18.3.9)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) '@radix-ui/react-dropdown-menu': specifier: ^2.0.6 - version: 2.1.1(@types/react-dom@19.0.0)(@types/react@18.3.9)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) + version: 2.1.1(@types/react-dom@19.0.2(@types/react@18.3.9))(@types/react@18.3.9)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) '@radix-ui/react-label': specifier: ^2.0.2 - version: 2.1.0(@types/react-dom@19.0.0)(@types/react@18.3.9)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) + version: 2.1.0(@types/react-dom@19.0.2(@types/react@18.3.9))(@types/react@18.3.9)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) '@radix-ui/react-navigation-menu': specifier: ^1.1.4 - version: 1.2.0(@types/react-dom@19.0.0)(@types/react@18.3.9)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) + version: 1.2.0(@types/react-dom@19.0.2(@types/react@18.3.9))(@types/react@18.3.9)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) '@radix-ui/react-popover': specifier: ^1.0.7 - version: 1.1.1(@types/react-dom@19.0.0)(@types/react@18.3.9)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) + version: 1.1.1(@types/react-dom@19.0.2(@types/react@18.3.9))(@types/react@18.3.9)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) '@radix-ui/react-slot': specifier: ^1.0.2 version: 1.1.0(@types/react@18.3.9)(react@18.3.1) '@radix-ui/react-switch': specifier: ^1.1.0 - version: 1.1.0(@types/react-dom@19.0.0)(@types/react@18.3.9)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) + version: 1.1.0(@types/react-dom@19.0.2(@types/react@18.3.9))(@types/react@18.3.9)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) '@tailwindcss/typography': specifier: ^0.5.9 version: 0.5.15(tailwindcss@3.4.13(ts-node@10.9.2(@types/node@20.16.9)(typescript@5.7.2))) @@ -841,7 +844,7 @@ importers: version: 18.3.9 '@types/react-dom': specifier: latest - version: 19.0.0 + version: 19.0.2(@types/react@18.3.9) '@vitejs/plugin-react': specifier: ^4.0.3 version: 4.3.1(vite@4.5.5(@types/node@20.16.9)(terser@5.34.0)) @@ -4294,10 +4297,10 @@ packages: react-dom: optional: true - '@storybook/builder-vite@8.5.0-alpha.18': - resolution: {integrity: sha512-jAfMwEt/mm469T3Vsx8E0xwCen8M+dd5zb87WUqgGbKZfle8xycZLNu2CvY6wlpIfxrLb+hHNRtFN/9W1i4Exg==} + '@storybook/builder-vite@8.5.0-beta.4': + resolution: {integrity: sha512-a4NFy6y2pfBMQWe4ZPCMh5/Fr3YMDeWWsPoc6KGXc5IbV0YMF8bPlQt3hLKRBGWQOR7C/VuuKnD4FE5CSHIbCA==} peerDependencies: - storybook: ^8.5.0-alpha.18 + storybook: ^8.5.0-beta.4 vite: ^4.0.0 || ^5.0.0 || ^6.0.0 '@storybook/core@8.3.3': @@ -4308,10 +4311,10 @@ packages: peerDependencies: storybook: ^8.3.3 - '@storybook/csf-plugin@8.5.0-alpha.18': - resolution: {integrity: sha512-RYwwErCZBUEjpryOHjFR8ZlQNxlo5LRRMiOroNFnyiG2Mpc76ztJ3v8i+frhTgEMKofWcrhnc+rFjmTHh46pTQ==} + '@storybook/csf-plugin@8.5.0-beta.4': + resolution: {integrity: sha512-b+V6hWSjo1g1jj+CQBm0br0/XAZ92NTEL7yiu3UuZsPZr27bNFysDEEpfxWjnlJP28z9R7VaHvMnEsQ5hRjdOA==} peerDependencies: - storybook: ^8.5.0-alpha.18 + storybook: ^8.5.0-beta.4 '@storybook/csf@0.1.11': resolution: {integrity: sha512-dHYFQH3mA+EtnCkHXzicbLgsvzYjcDJ1JWsogbItZogkPHgSJM/Wr71uMkcvw8v9mmCyP4NpXJuu6bPoVsOnzg==} @@ -4806,8 +4809,10 @@ packages: '@types/react-dom@18.3.0': resolution: {integrity: sha512-EhwApuTmMBmXuFOikhQLIBUn6uFg81SwLMOAUgodJF14SOBOCMdU04gDoYi0WOJJHD144TL32z4yDqCW3dnkQg==} - '@types/react-dom@19.0.0': - resolution: {integrity: sha512-1KfiQKsH1o00p9m5ag12axHQSb3FOU9H20UTrujVSkNhuCrRHiQWFqgEnTNK5ZNfnzZv8UWrnXVqCmCF9fgY3w==} + '@types/react-dom@19.0.2': + resolution: {integrity: sha512-c1s+7TKFaDRRxr1TxccIX2u7sfCnc3RxkVyBIUA2lCpyqCF+QoAwQ/CBg7bsMdVwP120HEH143VQezKtef5nCg==} + peerDependencies: + '@types/react': ^19.0.0 '@types/react-tooltip@4.2.4': resolution: {integrity: sha512-UzjzmgY/VH3Str6DcAGTLMA1mVVhGOyARNTANExrirtp+JgxhaIOVDxq4TIRmpSi4voLv+w4HA9CC5GvhhCA0A==} @@ -5861,6 +5866,11 @@ packages: resolution: {integrity: sha512-1VdUuRnQP4drdFkS8NKvDR1NBgevm8TOuflcaZEKsxw42CxonjW/2vkj1AKlinJb4ZLwBcuWF9GiPr7FQc6AQA==} engines: {node: '>=18.0'} + cross-env@7.0.3: + resolution: {integrity: sha512-+/HKd6EgcQCJGh2PSjZuUitQBQynKor4wrFbRg4DtAgS1aWO+gU52xpH7M9ScGgXSYmAVS9bIJ8EzuaGw0oNAw==} + engines: {node: '>=10.14', npm: '>=6', yarn: '>=1'} + hasBin: true + cross-fetch@3.1.8: resolution: {integrity: sha512-cvA+JwZoU0Xq+h6WkMvAUqPEYy92Obet6UdKLfW60qn99ftItKjB5T+BkyWOFWe2pUyfQ+IJHmpOTznqk1M6Kg==} @@ -6154,8 +6164,8 @@ packages: resolution: {integrity: sha512-xaBe6ZT4DHPkg0k4Ytbvn5xoxgpG0jOS1dYxSOwAHPuNLjP3/OzN0gH55SrLqpx8cBfSaVt91lXYkApjb+nYdQ==} engines: {node: '>=16'} - dotenv-cli@7.4.4: - resolution: {integrity: sha512-XkBYCG0tPIes+YZr4SpfFv76SQrV/LeCE8CI7JSEMi3VR9MvTihCGTOtbIexD6i2mXF+6px7trb1imVCXSNMDw==} + dotenv-cli@8.0.0: + resolution: {integrity: sha512-aLqYbK7xKOiTMIRf1lDPbI+Y+Ip/wo5k3eyp6ePysVaSqbyxjyK3dK35BTxG+rmd7djf5q2UPs4noPNH+cj0Qw==} hasBin: true dotenv-expand@10.0.0: @@ -13728,26 +13738,26 @@ snapshots: '@radix-ui/primitive@1.1.0': {} - '@radix-ui/react-arrow@1.1.0(@types/react-dom@19.0.0)(@types/react@18.3.9)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)': + '@radix-ui/react-arrow@1.1.0(@types/react-dom@19.0.2(@types/react@18.3.9))(@types/react@18.3.9)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)': dependencies: - '@radix-ui/react-primitive': 2.0.0(@types/react-dom@19.0.0)(@types/react@18.3.9)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) + '@radix-ui/react-primitive': 2.0.0(@types/react-dom@19.0.2(@types/react@18.3.9))(@types/react@18.3.9)(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) optionalDependencies: '@types/react': 18.3.9 - '@types/react-dom': 19.0.0 + '@types/react-dom': 19.0.2(@types/react@18.3.9) - '@radix-ui/react-collection@1.1.0(@types/react-dom@19.0.0)(@types/react@18.3.9)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)': + '@radix-ui/react-collection@1.1.0(@types/react-dom@19.0.2(@types/react@18.3.9))(@types/react@18.3.9)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)': dependencies: '@radix-ui/react-compose-refs': 1.1.0(@types/react@18.3.9)(react@18.3.1) '@radix-ui/react-context': 1.1.0(@types/react@18.3.9)(react@18.3.1) - '@radix-ui/react-primitive': 2.0.0(@types/react-dom@19.0.0)(@types/react@18.3.9)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) + '@radix-ui/react-primitive': 2.0.0(@types/react-dom@19.0.2(@types/react@18.3.9))(@types/react@18.3.9)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) '@radix-ui/react-slot': 1.1.0(@types/react@18.3.9)(react@18.3.1) react: 18.3.1 react-dom: 18.3.1(react@18.3.1) optionalDependencies: '@types/react': 18.3.9 - '@types/react-dom': 19.0.0 + '@types/react-dom': 19.0.2(@types/react@18.3.9) '@radix-ui/react-compose-refs@1.0.0(react@18.3.1)': dependencies: @@ -13800,18 +13810,18 @@ snapshots: transitivePeerDependencies: - '@types/react' - '@radix-ui/react-dialog@1.1.1(@types/react-dom@19.0.0)(@types/react@18.3.9)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)': + '@radix-ui/react-dialog@1.1.1(@types/react-dom@19.0.2(@types/react@18.3.9))(@types/react@18.3.9)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)': dependencies: '@radix-ui/primitive': 1.1.0 '@radix-ui/react-compose-refs': 1.1.0(@types/react@18.3.9)(react@18.3.1) '@radix-ui/react-context': 1.1.0(@types/react@18.3.9)(react@18.3.1) - '@radix-ui/react-dismissable-layer': 1.1.0(@types/react-dom@19.0.0)(@types/react@18.3.9)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) + '@radix-ui/react-dismissable-layer': 1.1.0(@types/react-dom@19.0.2(@types/react@18.3.9))(@types/react@18.3.9)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) '@radix-ui/react-focus-guards': 1.1.0(@types/react@18.3.9)(react@18.3.1) - '@radix-ui/react-focus-scope': 1.1.0(@types/react-dom@19.0.0)(@types/react@18.3.9)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) + '@radix-ui/react-focus-scope': 1.1.0(@types/react-dom@19.0.2(@types/react@18.3.9))(@types/react@18.3.9)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) '@radix-ui/react-id': 1.1.0(@types/react@18.3.9)(react@18.3.1) - '@radix-ui/react-portal': 1.1.1(@types/react-dom@19.0.0)(@types/react@18.3.9)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) - '@radix-ui/react-presence': 1.1.0(@types/react-dom@19.0.0)(@types/react@18.3.9)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) - '@radix-ui/react-primitive': 2.0.0(@types/react-dom@19.0.0)(@types/react@18.3.9)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) + '@radix-ui/react-portal': 1.1.1(@types/react-dom@19.0.2(@types/react@18.3.9))(@types/react@18.3.9)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) + '@radix-ui/react-presence': 1.1.0(@types/react-dom@19.0.2(@types/react@18.3.9))(@types/react@18.3.9)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) + '@radix-ui/react-primitive': 2.0.0(@types/react-dom@19.0.2(@types/react@18.3.9))(@types/react@18.3.9)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) '@radix-ui/react-slot': 1.1.0(@types/react@18.3.9)(react@18.3.1) '@radix-ui/react-use-controllable-state': 1.1.0(@types/react@18.3.9)(react@18.3.1) aria-hidden: 1.2.4 @@ -13820,7 +13830,7 @@ snapshots: react-remove-scroll: 2.5.7(@types/react@18.3.9)(react@18.3.1) optionalDependencies: '@types/react': 18.3.9 - '@types/react-dom': 19.0.0 + '@types/react-dom': 19.0.2(@types/react@18.3.9) '@radix-ui/react-direction@1.1.0(@types/react@18.3.9)(react@18.3.1)': dependencies: @@ -13839,33 +13849,33 @@ snapshots: react: 18.3.1 react-dom: 18.3.1(react@18.3.1) - '@radix-ui/react-dismissable-layer@1.1.0(@types/react-dom@19.0.0)(@types/react@18.3.9)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)': + '@radix-ui/react-dismissable-layer@1.1.0(@types/react-dom@19.0.2(@types/react@18.3.9))(@types/react@18.3.9)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)': dependencies: '@radix-ui/primitive': 1.1.0 '@radix-ui/react-compose-refs': 1.1.0(@types/react@18.3.9)(react@18.3.1) - '@radix-ui/react-primitive': 2.0.0(@types/react-dom@19.0.0)(@types/react@18.3.9)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) + '@radix-ui/react-primitive': 2.0.0(@types/react-dom@19.0.2(@types/react@18.3.9))(@types/react@18.3.9)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) '@radix-ui/react-use-callback-ref': 1.1.0(@types/react@18.3.9)(react@18.3.1) '@radix-ui/react-use-escape-keydown': 1.1.0(@types/react@18.3.9)(react@18.3.1) react: 18.3.1 react-dom: 18.3.1(react@18.3.1) optionalDependencies: '@types/react': 18.3.9 - '@types/react-dom': 19.0.0 + '@types/react-dom': 19.0.2(@types/react@18.3.9) - '@radix-ui/react-dropdown-menu@2.1.1(@types/react-dom@19.0.0)(@types/react@18.3.9)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)': + '@radix-ui/react-dropdown-menu@2.1.1(@types/react-dom@19.0.2(@types/react@18.3.9))(@types/react@18.3.9)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)': dependencies: '@radix-ui/primitive': 1.1.0 '@radix-ui/react-compose-refs': 1.1.0(@types/react@18.3.9)(react@18.3.1) '@radix-ui/react-context': 1.1.0(@types/react@18.3.9)(react@18.3.1) '@radix-ui/react-id': 1.1.0(@types/react@18.3.9)(react@18.3.1) - '@radix-ui/react-menu': 2.1.1(@types/react-dom@19.0.0)(@types/react@18.3.9)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) - '@radix-ui/react-primitive': 2.0.0(@types/react-dom@19.0.0)(@types/react@18.3.9)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) + '@radix-ui/react-menu': 2.1.1(@types/react-dom@19.0.2(@types/react@18.3.9))(@types/react@18.3.9)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) + '@radix-ui/react-primitive': 2.0.0(@types/react-dom@19.0.2(@types/react@18.3.9))(@types/react@18.3.9)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) '@radix-ui/react-use-controllable-state': 1.1.0(@types/react@18.3.9)(react@18.3.1) react: 18.3.1 react-dom: 18.3.1(react@18.3.1) optionalDependencies: '@types/react': 18.3.9 - '@types/react-dom': 19.0.0 + '@types/react-dom': 19.0.2(@types/react@18.3.9) '@radix-ui/react-focus-guards@1.0.0(react@18.3.1)': dependencies: @@ -13887,16 +13897,16 @@ snapshots: react: 18.3.1 react-dom: 18.3.1(react@18.3.1) - '@radix-ui/react-focus-scope@1.1.0(@types/react-dom@19.0.0)(@types/react@18.3.9)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)': + '@radix-ui/react-focus-scope@1.1.0(@types/react-dom@19.0.2(@types/react@18.3.9))(@types/react@18.3.9)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)': dependencies: '@radix-ui/react-compose-refs': 1.1.0(@types/react@18.3.9)(react@18.3.1) - '@radix-ui/react-primitive': 2.0.0(@types/react-dom@19.0.0)(@types/react@18.3.9)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) + '@radix-ui/react-primitive': 2.0.0(@types/react-dom@19.0.2(@types/react@18.3.9))(@types/react@18.3.9)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) '@radix-ui/react-use-callback-ref': 1.1.0(@types/react@18.3.9)(react@18.3.1) react: 18.3.1 react-dom: 18.3.1(react@18.3.1) optionalDependencies: '@types/react': 18.3.9 - '@types/react-dom': 19.0.0 + '@types/react-dom': 19.0.2(@types/react@18.3.9) '@radix-ui/react-id@1.0.0(react@18.3.1)': dependencies: @@ -13911,31 +13921,31 @@ snapshots: optionalDependencies: '@types/react': 18.3.9 - '@radix-ui/react-label@2.1.0(@types/react-dom@19.0.0)(@types/react@18.3.9)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)': + '@radix-ui/react-label@2.1.0(@types/react-dom@19.0.2(@types/react@18.3.9))(@types/react@18.3.9)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)': dependencies: - '@radix-ui/react-primitive': 2.0.0(@types/react-dom@19.0.0)(@types/react@18.3.9)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) + '@radix-ui/react-primitive': 2.0.0(@types/react-dom@19.0.2(@types/react@18.3.9))(@types/react@18.3.9)(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) optionalDependencies: '@types/react': 18.3.9 - '@types/react-dom': 19.0.0 + '@types/react-dom': 19.0.2(@types/react@18.3.9) - '@radix-ui/react-menu@2.1.1(@types/react-dom@19.0.0)(@types/react@18.3.9)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)': + '@radix-ui/react-menu@2.1.1(@types/react-dom@19.0.2(@types/react@18.3.9))(@types/react@18.3.9)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)': dependencies: '@radix-ui/primitive': 1.1.0 - '@radix-ui/react-collection': 1.1.0(@types/react-dom@19.0.0)(@types/react@18.3.9)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) + '@radix-ui/react-collection': 1.1.0(@types/react-dom@19.0.2(@types/react@18.3.9))(@types/react@18.3.9)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) '@radix-ui/react-compose-refs': 1.1.0(@types/react@18.3.9)(react@18.3.1) '@radix-ui/react-context': 1.1.0(@types/react@18.3.9)(react@18.3.1) '@radix-ui/react-direction': 1.1.0(@types/react@18.3.9)(react@18.3.1) - '@radix-ui/react-dismissable-layer': 1.1.0(@types/react-dom@19.0.0)(@types/react@18.3.9)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) + '@radix-ui/react-dismissable-layer': 1.1.0(@types/react-dom@19.0.2(@types/react@18.3.9))(@types/react@18.3.9)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) '@radix-ui/react-focus-guards': 1.1.0(@types/react@18.3.9)(react@18.3.1) - '@radix-ui/react-focus-scope': 1.1.0(@types/react-dom@19.0.0)(@types/react@18.3.9)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) + '@radix-ui/react-focus-scope': 1.1.0(@types/react-dom@19.0.2(@types/react@18.3.9))(@types/react@18.3.9)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) '@radix-ui/react-id': 1.1.0(@types/react@18.3.9)(react@18.3.1) - '@radix-ui/react-popper': 1.2.0(@types/react-dom@19.0.0)(@types/react@18.3.9)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) - '@radix-ui/react-portal': 1.1.1(@types/react-dom@19.0.0)(@types/react@18.3.9)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) - '@radix-ui/react-presence': 1.1.0(@types/react-dom@19.0.0)(@types/react@18.3.9)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) - '@radix-ui/react-primitive': 2.0.0(@types/react-dom@19.0.0)(@types/react@18.3.9)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) - '@radix-ui/react-roving-focus': 1.1.0(@types/react-dom@19.0.0)(@types/react@18.3.9)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) + '@radix-ui/react-popper': 1.2.0(@types/react-dom@19.0.2(@types/react@18.3.9))(@types/react@18.3.9)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) + '@radix-ui/react-portal': 1.1.1(@types/react-dom@19.0.2(@types/react@18.3.9))(@types/react@18.3.9)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) + '@radix-ui/react-presence': 1.1.0(@types/react-dom@19.0.2(@types/react@18.3.9))(@types/react@18.3.9)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) + '@radix-ui/react-primitive': 2.0.0(@types/react-dom@19.0.2(@types/react@18.3.9))(@types/react@18.3.9)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) + '@radix-ui/react-roving-focus': 1.1.0(@types/react-dom@19.0.2(@types/react@18.3.9))(@types/react@18.3.9)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) '@radix-ui/react-slot': 1.1.0(@types/react@18.3.9)(react@18.3.1) '@radix-ui/react-use-callback-ref': 1.1.0(@types/react@18.3.9)(react@18.3.1) aria-hidden: 1.2.4 @@ -13944,43 +13954,43 @@ snapshots: react-remove-scroll: 2.5.7(@types/react@18.3.9)(react@18.3.1) optionalDependencies: '@types/react': 18.3.9 - '@types/react-dom': 19.0.0 + '@types/react-dom': 19.0.2(@types/react@18.3.9) - '@radix-ui/react-navigation-menu@1.2.0(@types/react-dom@19.0.0)(@types/react@18.3.9)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)': + '@radix-ui/react-navigation-menu@1.2.0(@types/react-dom@19.0.2(@types/react@18.3.9))(@types/react@18.3.9)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)': dependencies: '@radix-ui/primitive': 1.1.0 - '@radix-ui/react-collection': 1.1.0(@types/react-dom@19.0.0)(@types/react@18.3.9)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) + '@radix-ui/react-collection': 1.1.0(@types/react-dom@19.0.2(@types/react@18.3.9))(@types/react@18.3.9)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) '@radix-ui/react-compose-refs': 1.1.0(@types/react@18.3.9)(react@18.3.1) '@radix-ui/react-context': 1.1.0(@types/react@18.3.9)(react@18.3.1) '@radix-ui/react-direction': 1.1.0(@types/react@18.3.9)(react@18.3.1) - '@radix-ui/react-dismissable-layer': 1.1.0(@types/react-dom@19.0.0)(@types/react@18.3.9)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) + '@radix-ui/react-dismissable-layer': 1.1.0(@types/react-dom@19.0.2(@types/react@18.3.9))(@types/react@18.3.9)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) '@radix-ui/react-id': 1.1.0(@types/react@18.3.9)(react@18.3.1) - '@radix-ui/react-presence': 1.1.0(@types/react-dom@19.0.0)(@types/react@18.3.9)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) - '@radix-ui/react-primitive': 2.0.0(@types/react-dom@19.0.0)(@types/react@18.3.9)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) + '@radix-ui/react-presence': 1.1.0(@types/react-dom@19.0.2(@types/react@18.3.9))(@types/react@18.3.9)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) + '@radix-ui/react-primitive': 2.0.0(@types/react-dom@19.0.2(@types/react@18.3.9))(@types/react@18.3.9)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) '@radix-ui/react-use-callback-ref': 1.1.0(@types/react@18.3.9)(react@18.3.1) '@radix-ui/react-use-controllable-state': 1.1.0(@types/react@18.3.9)(react@18.3.1) '@radix-ui/react-use-layout-effect': 1.1.0(@types/react@18.3.9)(react@18.3.1) '@radix-ui/react-use-previous': 1.1.0(@types/react@18.3.9)(react@18.3.1) - '@radix-ui/react-visually-hidden': 1.1.0(@types/react-dom@19.0.0)(@types/react@18.3.9)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) + '@radix-ui/react-visually-hidden': 1.1.0(@types/react-dom@19.0.2(@types/react@18.3.9))(@types/react@18.3.9)(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) optionalDependencies: '@types/react': 18.3.9 - '@types/react-dom': 19.0.0 + '@types/react-dom': 19.0.2(@types/react@18.3.9) - '@radix-ui/react-popover@1.1.1(@types/react-dom@19.0.0)(@types/react@18.3.9)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)': + '@radix-ui/react-popover@1.1.1(@types/react-dom@19.0.2(@types/react@18.3.9))(@types/react@18.3.9)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)': dependencies: '@radix-ui/primitive': 1.1.0 '@radix-ui/react-compose-refs': 1.1.0(@types/react@18.3.9)(react@18.3.1) '@radix-ui/react-context': 1.1.0(@types/react@18.3.9)(react@18.3.1) - '@radix-ui/react-dismissable-layer': 1.1.0(@types/react-dom@19.0.0)(@types/react@18.3.9)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) + '@radix-ui/react-dismissable-layer': 1.1.0(@types/react-dom@19.0.2(@types/react@18.3.9))(@types/react@18.3.9)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) '@radix-ui/react-focus-guards': 1.1.0(@types/react@18.3.9)(react@18.3.1) - '@radix-ui/react-focus-scope': 1.1.0(@types/react-dom@19.0.0)(@types/react@18.3.9)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) + '@radix-ui/react-focus-scope': 1.1.0(@types/react-dom@19.0.2(@types/react@18.3.9))(@types/react@18.3.9)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) '@radix-ui/react-id': 1.1.0(@types/react@18.3.9)(react@18.3.1) - '@radix-ui/react-popper': 1.2.0(@types/react-dom@19.0.0)(@types/react@18.3.9)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) - '@radix-ui/react-portal': 1.1.1(@types/react-dom@19.0.0)(@types/react@18.3.9)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) - '@radix-ui/react-presence': 1.1.0(@types/react-dom@19.0.0)(@types/react@18.3.9)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) - '@radix-ui/react-primitive': 2.0.0(@types/react-dom@19.0.0)(@types/react@18.3.9)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) + '@radix-ui/react-popper': 1.2.0(@types/react-dom@19.0.2(@types/react@18.3.9))(@types/react@18.3.9)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) + '@radix-ui/react-portal': 1.1.1(@types/react-dom@19.0.2(@types/react@18.3.9))(@types/react@18.3.9)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) + '@radix-ui/react-presence': 1.1.0(@types/react-dom@19.0.2(@types/react@18.3.9))(@types/react@18.3.9)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) + '@radix-ui/react-primitive': 2.0.0(@types/react-dom@19.0.2(@types/react@18.3.9))(@types/react@18.3.9)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) '@radix-ui/react-slot': 1.1.0(@types/react@18.3.9)(react@18.3.1) '@radix-ui/react-use-controllable-state': 1.1.0(@types/react@18.3.9)(react@18.3.1) aria-hidden: 1.2.4 @@ -13989,15 +13999,15 @@ snapshots: react-remove-scroll: 2.5.7(@types/react@18.3.9)(react@18.3.1) optionalDependencies: '@types/react': 18.3.9 - '@types/react-dom': 19.0.0 + '@types/react-dom': 19.0.2(@types/react@18.3.9) - '@radix-ui/react-popper@1.2.0(@types/react-dom@19.0.0)(@types/react@18.3.9)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)': + '@radix-ui/react-popper@1.2.0(@types/react-dom@19.0.2(@types/react@18.3.9))(@types/react@18.3.9)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)': dependencies: '@floating-ui/react-dom': 2.1.2(react-dom@18.3.1(react@18.3.1))(react@18.3.1) - '@radix-ui/react-arrow': 1.1.0(@types/react-dom@19.0.0)(@types/react@18.3.9)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) + '@radix-ui/react-arrow': 1.1.0(@types/react-dom@19.0.2(@types/react@18.3.9))(@types/react@18.3.9)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) '@radix-ui/react-compose-refs': 1.1.0(@types/react@18.3.9)(react@18.3.1) '@radix-ui/react-context': 1.1.0(@types/react@18.3.9)(react@18.3.1) - '@radix-ui/react-primitive': 2.0.0(@types/react-dom@19.0.0)(@types/react@18.3.9)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) + '@radix-ui/react-primitive': 2.0.0(@types/react-dom@19.0.2(@types/react@18.3.9))(@types/react@18.3.9)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) '@radix-ui/react-use-callback-ref': 1.1.0(@types/react@18.3.9)(react@18.3.1) '@radix-ui/react-use-layout-effect': 1.1.0(@types/react@18.3.9)(react@18.3.1) '@radix-ui/react-use-rect': 1.1.0(@types/react@18.3.9)(react@18.3.1) @@ -14007,7 +14017,7 @@ snapshots: react-dom: 18.3.1(react@18.3.1) optionalDependencies: '@types/react': 18.3.9 - '@types/react-dom': 19.0.0 + '@types/react-dom': 19.0.2(@types/react@18.3.9) '@radix-ui/react-portal@1.0.0(react-dom@18.3.1(react@18.3.1))(react@18.3.1)': dependencies: @@ -14016,15 +14026,15 @@ snapshots: react: 18.3.1 react-dom: 18.3.1(react@18.3.1) - '@radix-ui/react-portal@1.1.1(@types/react-dom@19.0.0)(@types/react@18.3.9)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)': + '@radix-ui/react-portal@1.1.1(@types/react-dom@19.0.2(@types/react@18.3.9))(@types/react@18.3.9)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)': dependencies: - '@radix-ui/react-primitive': 2.0.0(@types/react-dom@19.0.0)(@types/react@18.3.9)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) + '@radix-ui/react-primitive': 2.0.0(@types/react-dom@19.0.2(@types/react@18.3.9))(@types/react@18.3.9)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) '@radix-ui/react-use-layout-effect': 1.1.0(@types/react@18.3.9)(react@18.3.1) react: 18.3.1 react-dom: 18.3.1(react@18.3.1) optionalDependencies: '@types/react': 18.3.9 - '@types/react-dom': 19.0.0 + '@types/react-dom': 19.0.2(@types/react@18.3.9) '@radix-ui/react-presence@1.0.0(react-dom@18.3.1(react@18.3.1))(react@18.3.1)': dependencies: @@ -14034,7 +14044,7 @@ snapshots: react: 18.3.1 react-dom: 18.3.1(react@18.3.1) - '@radix-ui/react-presence@1.1.0(@types/react-dom@19.0.0)(@types/react@18.3.9)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)': + '@radix-ui/react-presence@1.1.0(@types/react-dom@19.0.2(@types/react@18.3.9))(@types/react@18.3.9)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)': dependencies: '@radix-ui/react-compose-refs': 1.1.0(@types/react@18.3.9)(react@18.3.1) '@radix-ui/react-use-layout-effect': 1.1.0(@types/react@18.3.9)(react@18.3.1) @@ -14042,7 +14052,7 @@ snapshots: react-dom: 18.3.1(react@18.3.1) optionalDependencies: '@types/react': 18.3.9 - '@types/react-dom': 19.0.0 + '@types/react-dom': 19.0.2(@types/react@18.3.9) '@radix-ui/react-primitive@1.0.0(react-dom@18.3.1(react@18.3.1))(react@18.3.1)': dependencies: @@ -14051,31 +14061,31 @@ snapshots: react: 18.3.1 react-dom: 18.3.1(react@18.3.1) - '@radix-ui/react-primitive@2.0.0(@types/react-dom@19.0.0)(@types/react@18.3.9)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)': + '@radix-ui/react-primitive@2.0.0(@types/react-dom@19.0.2(@types/react@18.3.9))(@types/react@18.3.9)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)': dependencies: '@radix-ui/react-slot': 1.1.0(@types/react@18.3.9)(react@18.3.1) react: 18.3.1 react-dom: 18.3.1(react@18.3.1) optionalDependencies: '@types/react': 18.3.9 - '@types/react-dom': 19.0.0 + '@types/react-dom': 19.0.2(@types/react@18.3.9) - '@radix-ui/react-roving-focus@1.1.0(@types/react-dom@19.0.0)(@types/react@18.3.9)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)': + '@radix-ui/react-roving-focus@1.1.0(@types/react-dom@19.0.2(@types/react@18.3.9))(@types/react@18.3.9)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)': dependencies: '@radix-ui/primitive': 1.1.0 - '@radix-ui/react-collection': 1.1.0(@types/react-dom@19.0.0)(@types/react@18.3.9)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) + '@radix-ui/react-collection': 1.1.0(@types/react-dom@19.0.2(@types/react@18.3.9))(@types/react@18.3.9)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) '@radix-ui/react-compose-refs': 1.1.0(@types/react@18.3.9)(react@18.3.1) '@radix-ui/react-context': 1.1.0(@types/react@18.3.9)(react@18.3.1) '@radix-ui/react-direction': 1.1.0(@types/react@18.3.9)(react@18.3.1) '@radix-ui/react-id': 1.1.0(@types/react@18.3.9)(react@18.3.1) - '@radix-ui/react-primitive': 2.0.0(@types/react-dom@19.0.0)(@types/react@18.3.9)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) + '@radix-ui/react-primitive': 2.0.0(@types/react-dom@19.0.2(@types/react@18.3.9))(@types/react@18.3.9)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) '@radix-ui/react-use-callback-ref': 1.1.0(@types/react@18.3.9)(react@18.3.1) '@radix-ui/react-use-controllable-state': 1.1.0(@types/react@18.3.9)(react@18.3.1) react: 18.3.1 react-dom: 18.3.1(react@18.3.1) optionalDependencies: '@types/react': 18.3.9 - '@types/react-dom': 19.0.0 + '@types/react-dom': 19.0.2(@types/react@18.3.9) '@radix-ui/react-slot@1.0.0(react@18.3.1)': dependencies: @@ -14098,12 +14108,12 @@ snapshots: optionalDependencies: '@types/react': 18.3.9 - '@radix-ui/react-switch@1.1.0(@types/react-dom@19.0.0)(@types/react@18.3.9)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)': + '@radix-ui/react-switch@1.1.0(@types/react-dom@19.0.2(@types/react@18.3.9))(@types/react@18.3.9)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)': dependencies: '@radix-ui/primitive': 1.1.0 '@radix-ui/react-compose-refs': 1.1.0(@types/react@18.3.9)(react@18.3.1) '@radix-ui/react-context': 1.1.0(@types/react@18.3.9)(react@18.3.1) - '@radix-ui/react-primitive': 2.0.0(@types/react-dom@19.0.0)(@types/react@18.3.9)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) + '@radix-ui/react-primitive': 2.0.0(@types/react-dom@19.0.2(@types/react@18.3.9))(@types/react@18.3.9)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) '@radix-ui/react-use-controllable-state': 1.1.0(@types/react@18.3.9)(react@18.3.1) '@radix-ui/react-use-previous': 1.1.0(@types/react@18.3.9)(react@18.3.1) '@radix-ui/react-use-size': 1.1.0(@types/react@18.3.9)(react@18.3.1) @@ -14111,7 +14121,7 @@ snapshots: react-dom: 18.3.1(react@18.3.1) optionalDependencies: '@types/react': 18.3.9 - '@types/react-dom': 19.0.0 + '@types/react-dom': 19.0.2(@types/react@18.3.9) '@radix-ui/react-use-callback-ref@1.0.0(react@18.3.1)': dependencies: @@ -14181,14 +14191,14 @@ snapshots: optionalDependencies: '@types/react': 18.3.9 - '@radix-ui/react-visually-hidden@1.1.0(@types/react-dom@19.0.0)(@types/react@18.3.9)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)': + '@radix-ui/react-visually-hidden@1.1.0(@types/react-dom@19.0.2(@types/react@18.3.9))(@types/react@18.3.9)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)': dependencies: - '@radix-ui/react-primitive': 2.0.0(@types/react-dom@19.0.0)(@types/react@18.3.9)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) + '@radix-ui/react-primitive': 2.0.0(@types/react-dom@19.0.2(@types/react@18.3.9))(@types/react@18.3.9)(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) optionalDependencies: '@types/react': 18.3.9 - '@types/react-dom': 19.0.0 + '@types/react-dom': 19.0.2(@types/react@18.3.9) '@radix-ui/rect@1.1.0': {} @@ -15036,9 +15046,9 @@ snapshots: react: 18.3.1 react-dom: 18.3.1(react@18.3.1) - '@storybook/builder-vite@8.5.0-alpha.18(storybook@8.3.3)(vite@5.4.8(@types/node@20.16.9)(terser@5.34.0))': + '@storybook/builder-vite@8.5.0-beta.4(storybook@8.3.3)(vite@5.4.8(@types/node@20.16.9)(terser@5.34.0))': dependencies: - '@storybook/csf-plugin': 8.5.0-alpha.18(storybook@8.3.3) + '@storybook/csf-plugin': 8.5.0-beta.4(storybook@8.3.3) browser-assert: 1.2.1 storybook: 8.3.3 ts-dedent: 2.2.0 @@ -15069,7 +15079,7 @@ snapshots: storybook: 8.3.3 unplugin: 1.16.0 - '@storybook/csf-plugin@8.5.0-alpha.18(storybook@8.3.3)': + '@storybook/csf-plugin@8.5.0-beta.4(storybook@8.3.3)': dependencies: storybook: 8.3.3 unplugin: 1.16.0 @@ -15607,7 +15617,7 @@ snapshots: dependencies: '@types/react': 18.3.9 - '@types/react-dom@19.0.0': + '@types/react-dom@19.0.2(@types/react@18.3.9)': dependencies: '@types/react': 18.3.9 @@ -16917,6 +16927,10 @@ snapshots: croner@8.1.1: {} + cross-env@7.0.3: + dependencies: + cross-spawn: 7.0.6 + cross-fetch@3.1.8: dependencies: node-fetch: 2.7.0 @@ -17180,7 +17194,7 @@ snapshots: dependencies: type-fest: 3.13.1 - dotenv-cli@7.4.4: + dotenv-cli@8.0.0: dependencies: cross-spawn: 7.0.6 dotenv: 16.4.5 @@ -17622,7 +17636,7 @@ snapshots: optionalDependencies: source-map: 0.6.1 - eslint-config-airbnb-base@15.0.0(eslint-plugin-import@2.30.0)(eslint@8.57.1): + eslint-config-airbnb-base@15.0.0(eslint-plugin-import@2.30.0(@typescript-eslint/parser@7.18.0(eslint@8.57.1)(typescript@5.7.2))(eslint-import-resolver-typescript@3.6.3)(eslint@8.57.1))(eslint@8.57.1): dependencies: confusing-browser-globals: 1.0.11 eslint: 8.57.1 @@ -17631,12 +17645,12 @@ snapshots: object.entries: 1.1.8 semver: 6.3.1 - eslint-config-airbnb-typescript@18.0.0(@typescript-eslint/eslint-plugin@7.18.0(@typescript-eslint/parser@7.18.0(eslint@8.57.1)(typescript@5.7.2))(eslint@8.57.1)(typescript@5.7.2))(@typescript-eslint/parser@7.18.0(eslint@8.57.1)(typescript@5.7.2))(eslint-plugin-import@2.30.0)(eslint@8.57.1): + eslint-config-airbnb-typescript@18.0.0(@typescript-eslint/eslint-plugin@7.18.0(@typescript-eslint/parser@7.18.0(eslint@8.57.1)(typescript@5.7.2))(eslint@8.57.1)(typescript@5.7.2))(@typescript-eslint/parser@7.18.0(eslint@8.57.1)(typescript@5.7.2))(eslint-plugin-import@2.30.0(@typescript-eslint/parser@7.18.0(eslint@8.57.1)(typescript@5.7.2))(eslint-import-resolver-typescript@3.6.3)(eslint@8.57.1))(eslint@8.57.1): dependencies: '@typescript-eslint/eslint-plugin': 7.18.0(@typescript-eslint/parser@7.18.0(eslint@8.57.1)(typescript@5.7.2))(eslint@8.57.1)(typescript@5.7.2) '@typescript-eslint/parser': 7.18.0(eslint@8.57.1)(typescript@5.7.2) eslint: 8.57.1 - eslint-config-airbnb-base: 15.0.0(eslint-plugin-import@2.30.0)(eslint@8.57.1) + eslint-config-airbnb-base: 15.0.0(eslint-plugin-import@2.30.0(@typescript-eslint/parser@7.18.0(eslint@8.57.1)(typescript@5.7.2))(eslint-import-resolver-typescript@3.6.3)(eslint@8.57.1))(eslint@8.57.1) transitivePeerDependencies: - eslint-plugin-import @@ -17666,7 +17680,7 @@ snapshots: '@typescript-eslint/parser': 5.62.0(eslint@8.57.1)(typescript@5.7.2) eslint: 8.57.1 eslint-import-resolver-node: 0.3.9 - eslint-import-resolver-typescript: 3.6.3(@typescript-eslint/parser@5.62.0(eslint@8.57.1)(typescript@5.7.2))(eslint-import-resolver-node@0.3.9)(eslint-plugin-import@2.30.0)(eslint@8.57.1) + eslint-import-resolver-typescript: 3.6.3(@typescript-eslint/parser@5.62.0(eslint@8.57.1)(typescript@5.7.2))(eslint-import-resolver-node@0.3.9)(eslint-plugin-import@2.30.0(eslint@8.57.1))(eslint@8.57.1) eslint-plugin-import: 2.30.0(@typescript-eslint/parser@5.62.0(eslint@8.57.1)(typescript@5.7.2))(eslint-import-resolver-typescript@3.6.3)(eslint@8.57.1) eslint-plugin-jsx-a11y: 6.10.0(eslint@8.57.1) eslint-plugin-react: 7.37.0(eslint@8.57.1) @@ -17695,13 +17709,32 @@ snapshots: transitivePeerDependencies: - supports-color + eslint-import-resolver-typescript@3.6.3(@typescript-eslint/parser@5.62.0(eslint@8.57.1)(typescript@5.7.2))(eslint-import-resolver-node@0.3.9)(eslint-plugin-import@2.30.0(eslint@8.57.1))(eslint@8.57.1): + dependencies: + '@nolyfill/is-core-module': 1.0.39 + debug: 4.3.7(supports-color@5.5.0) + enhanced-resolve: 5.17.1 + eslint: 8.57.1 + eslint-module-utils: 2.12.0(@typescript-eslint/parser@5.62.0(eslint@8.57.1)(typescript@5.7.2))(eslint-import-resolver-node@0.3.9)(eslint-import-resolver-typescript@3.6.3(@typescript-eslint/parser@5.62.0(eslint@8.57.1)(typescript@5.7.2))(eslint-import-resolver-node@0.3.9)(eslint-plugin-import@2.30.0(eslint@8.57.1))(eslint@8.57.1))(eslint@8.57.1) + fast-glob: 3.3.2 + get-tsconfig: 4.8.1 + is-bun-module: 1.2.1 + is-glob: 4.0.3 + optionalDependencies: + eslint-plugin-import: 2.30.0(@typescript-eslint/parser@5.62.0(eslint@8.57.1)(typescript@5.7.2))(eslint-import-resolver-typescript@3.6.3)(eslint@8.57.1) + transitivePeerDependencies: + - '@typescript-eslint/parser' + - eslint-import-resolver-node + - eslint-import-resolver-webpack + - supports-color + eslint-import-resolver-typescript@3.6.3(@typescript-eslint/parser@5.62.0(eslint@8.57.1)(typescript@5.7.2))(eslint-import-resolver-node@0.3.9)(eslint-plugin-import@2.30.0)(eslint@8.57.1): dependencies: '@nolyfill/is-core-module': 1.0.39 debug: 4.3.7(supports-color@5.5.0) enhanced-resolve: 5.17.1 eslint: 8.57.1 - eslint-module-utils: 2.12.0(@typescript-eslint/parser@5.62.0(eslint@8.57.1)(typescript@5.7.2))(eslint-import-resolver-node@0.3.9)(eslint-import-resolver-typescript@3.6.3)(eslint@8.57.1) + eslint-module-utils: 2.12.0(@typescript-eslint/parser@5.62.0(eslint@8.57.1)(typescript@5.7.2))(eslint-import-resolver-node@0.3.9)(eslint-import-resolver-typescript@3.6.3(@typescript-eslint/parser@5.62.0(eslint@8.57.1)(typescript@5.7.2))(eslint-import-resolver-node@0.3.9)(eslint-plugin-import@2.30.0)(eslint@8.57.1))(eslint@8.57.1) fast-glob: 3.3.2 get-tsconfig: 4.8.1 is-bun-module: 1.2.1 @@ -17720,7 +17753,7 @@ snapshots: debug: 4.3.7(supports-color@5.5.0) enhanced-resolve: 5.17.1 eslint: 8.57.1 - eslint-module-utils: 2.12.0(@typescript-eslint/parser@7.18.0(eslint@8.57.1)(typescript@5.7.2))(eslint-import-resolver-node@0.3.9)(eslint-import-resolver-typescript@3.6.3)(eslint@8.57.1) + eslint-module-utils: 2.12.0(@typescript-eslint/parser@7.18.0(eslint@8.57.1)(typescript@5.7.2))(eslint-import-resolver-node@0.3.9)(eslint-import-resolver-typescript@3.6.3(@typescript-eslint/parser@7.18.0(eslint@8.57.1)(typescript@5.7.2))(eslint-plugin-import@2.30.0)(eslint@8.57.1))(eslint@8.57.1) fast-glob: 3.3.2 get-tsconfig: 4.8.1 is-bun-module: 1.2.1 @@ -17733,7 +17766,18 @@ snapshots: - eslint-import-resolver-webpack - supports-color - eslint-module-utils@2.12.0(@typescript-eslint/parser@5.62.0(eslint@8.57.1)(typescript@5.7.2))(eslint-import-resolver-node@0.3.9)(eslint-import-resolver-typescript@3.6.3)(eslint@8.57.1): + eslint-module-utils@2.12.0(@typescript-eslint/parser@5.62.0(eslint@8.57.1)(typescript@5.7.2))(eslint-import-resolver-node@0.3.9)(eslint-import-resolver-typescript@3.6.3(@typescript-eslint/parser@5.62.0(eslint@8.57.1)(typescript@5.7.2))(eslint-import-resolver-node@0.3.9)(eslint-plugin-import@2.30.0(eslint@8.57.1))(eslint@8.57.1))(eslint@8.57.1): + dependencies: + debug: 3.2.7 + optionalDependencies: + '@typescript-eslint/parser': 5.62.0(eslint@8.57.1)(typescript@5.7.2) + eslint: 8.57.1 + eslint-import-resolver-node: 0.3.9 + eslint-import-resolver-typescript: 3.6.3(@typescript-eslint/parser@5.62.0(eslint@8.57.1)(typescript@5.7.2))(eslint-import-resolver-node@0.3.9)(eslint-plugin-import@2.30.0(eslint@8.57.1))(eslint@8.57.1) + transitivePeerDependencies: + - supports-color + + eslint-module-utils@2.12.0(@typescript-eslint/parser@5.62.0(eslint@8.57.1)(typescript@5.7.2))(eslint-import-resolver-node@0.3.9)(eslint-import-resolver-typescript@3.6.3(@typescript-eslint/parser@5.62.0(eslint@8.57.1)(typescript@5.7.2))(eslint-import-resolver-node@0.3.9)(eslint-plugin-import@2.30.0)(eslint@8.57.1))(eslint@8.57.1): dependencies: debug: 3.2.7 optionalDependencies: @@ -17744,7 +17788,7 @@ snapshots: transitivePeerDependencies: - supports-color - eslint-module-utils@2.12.0(@typescript-eslint/parser@7.18.0(eslint@8.57.1)(typescript@5.7.2))(eslint-import-resolver-node@0.3.9)(eslint-import-resolver-typescript@3.6.3)(eslint@8.57.1): + eslint-module-utils@2.12.0(@typescript-eslint/parser@7.18.0(eslint@8.57.1)(typescript@5.7.2))(eslint-import-resolver-node@0.3.9)(eslint-import-resolver-typescript@3.6.3(@typescript-eslint/parser@7.18.0(eslint@8.57.1)(typescript@5.7.2))(eslint-plugin-import@2.30.0)(eslint@8.57.1))(eslint@8.57.1): dependencies: debug: 3.2.7 optionalDependencies: @@ -17766,7 +17810,7 @@ snapshots: doctrine: 2.1.0 eslint: 8.57.1 eslint-import-resolver-node: 0.3.9 - eslint-module-utils: 2.12.0(@typescript-eslint/parser@5.62.0(eslint@8.57.1)(typescript@5.7.2))(eslint-import-resolver-node@0.3.9)(eslint-import-resolver-typescript@3.6.3)(eslint@8.57.1) + eslint-module-utils: 2.12.0(@typescript-eslint/parser@5.62.0(eslint@8.57.1)(typescript@5.7.2))(eslint-import-resolver-node@0.3.9)(eslint-import-resolver-typescript@3.6.3(@typescript-eslint/parser@5.62.0(eslint@8.57.1)(typescript@5.7.2))(eslint-import-resolver-node@0.3.9)(eslint-plugin-import@2.30.0)(eslint@8.57.1))(eslint@8.57.1) hasown: 2.0.2 is-core-module: 2.15.1 is-glob: 4.0.3 @@ -17794,7 +17838,7 @@ snapshots: doctrine: 2.1.0 eslint: 8.57.1 eslint-import-resolver-node: 0.3.9 - eslint-module-utils: 2.12.0(@typescript-eslint/parser@7.18.0(eslint@8.57.1)(typescript@5.7.2))(eslint-import-resolver-node@0.3.9)(eslint-import-resolver-typescript@3.6.3)(eslint@8.57.1) + eslint-module-utils: 2.12.0(@typescript-eslint/parser@7.18.0(eslint@8.57.1)(typescript@5.7.2))(eslint-import-resolver-node@0.3.9)(eslint-import-resolver-typescript@3.6.3(@typescript-eslint/parser@7.18.0(eslint@8.57.1)(typescript@5.7.2))(eslint-plugin-import@2.30.0)(eslint@8.57.1))(eslint@8.57.1) hasown: 2.0.2 is-core-module: 2.15.1 is-glob: 4.0.3 @@ -18103,7 +18147,7 @@ snapshots: execa@5.1.1: dependencies: - cross-spawn: 7.0.3 + cross-spawn: 7.0.6 get-stream: 6.0.1 human-signals: 2.1.0 is-stream: 2.0.1 @@ -18115,7 +18159,7 @@ snapshots: execa@8.0.1: dependencies: - cross-spawn: 7.0.3 + cross-spawn: 7.0.6 get-stream: 8.0.1 human-signals: 5.0.0 is-stream: 3.0.0 @@ -18306,7 +18350,7 @@ snapshots: foreground-child@3.3.0: dependencies: - cross-spawn: 7.0.3 + cross-spawn: 7.0.6 signal-exit: 4.1.0 form-data-encoder@1.7.2: {} @@ -22573,7 +22617,7 @@ snapshots: storybook-solidjs-vite@1.0.0-beta.2(storybook@8.3.3)(vite@5.4.8(@types/node@20.16.9)(terser@5.34.0)): dependencies: - '@storybook/builder-vite': 8.5.0-alpha.18(storybook@8.3.3)(vite@5.4.8(@types/node@20.16.9)(terser@5.34.0)) + '@storybook/builder-vite': 8.5.0-beta.4(storybook@8.3.3)(vite@5.4.8(@types/node@20.16.9)(terser@5.34.0)) transitivePeerDependencies: - storybook - vite