From 6ec0a84b2306d80d286378d395ecdae9e7fbc6cc Mon Sep 17 00:00:00 2001 From: jamals86 Date: Tue, 5 May 2026 14:13:36 +0300 Subject: [PATCH] Improve restart recovery, snowflake batching, & CI Introduce restart-recovery improvements and various optimizations across the codebase. Key changes: reconcile and persist in-memory state-machine progress from persisted last_applied (KalamRaftStorage, RaftGroup, RaftManager) and emit clearer replication timeout details; commit last_applied while applying entries and return errors for apply failures to avoid silent progress. Add SnowflakeGenerator::next_ids_mapped to avoid intermediate allocations and wire it into system SeqId generation + new benchmarks and tests for mapped and concurrent generation. Fix embedded UI asset serving to avoid unnecessary copies, tweak websocket heartbeat handling, add deterministic initial-row sorting and tests, and adjust health monitor trimming logic. CI and developer tooling: set test env vars and add verification for TypeScript package test coverage in workflows, add new TypeScript ORM files and UI component updates, and change Docker base image to Ubuntu 24.04. --- .config/nextest.toml | 5 +- .github/workflows/orm.yml | 2 + .github/workflows/sdks.yml | 15 +- backend/crates/kalamdb-api/src/ui/embedded.rs | 13 +- backend/crates/kalamdb-api/src/ws/runtime.rs | 2 - .../benches/snowflake_generator.rs | 185 +- .../kalamdb-commons/src/ids/snowflake.rs | 48 +- .../crates/kalamdb-jobs/src/health_monitor.rs | 13 +- .../kalamdb-live/src/helpers/initial_data.rs | 94 +- backend/crates/kalamdb-raft/src/error.rs | 10 +- .../kalamdb-raft/src/manager/raft_group.rs | 58 +- .../kalamdb-raft/src/manager/raft_manager.rs | 18 +- .../kalamdb-raft/src/state_machine/meta.rs | 3 +- .../src/state_machine/shared_data.rs | 4 +- .../src/state_machine/user_data.rs | 4 +- .../kalamdb-raft/src/storage/raft_store.rs | 300 ++- .../src/services/system_columns_service.rs | 5 +- docker/build/Dockerfile.prebuilt | 4 +- .../loading_resume_with_live_writes.rs | 13 +- link/link-common/src/client/runtime.rs | 3 +- .../src/connection/shared/reconnect.rs | 2 + .../src/connection/shared/routing.rs | 47 +- .../src/subscription/checkpoint.rs | 21 +- link/link-common/src/subscription/manager.rs | 44 +- link/sdks/typescript/orm/README.md | 36 +- link/sdks/typescript/orm/package.json | 2 +- link/sdks/typescript/orm/src/driver.ts | 3 +- .../typescript/orm/src/query-normalize.ts | 35 + link/sdks/typescript/orm/src/sql.ts | 3 +- link/sdks/typescript/orm/tests/helpers.mjs | 4 +- .../orm/tests/sql-normalize.test.mjs | 18 + nextest.toml | 5 +- ui/components.json | 9 +- ui/eslint.config.js | 40 + ui/package-lock.json | 2061 +++++++++++------ ui/package.json | 51 +- .../preview/StudioResultsGrid.tsx | 6 +- .../table-editor/EditorSidebar.tsx | 2 +- ui/src/components/ui/alert.tsx | 104 +- ui/src/components/ui/badge.tsx | 35 +- ui/src/components/ui/button.tsx | 71 +- ui/src/components/ui/card.tsx | 163 +- ui/src/components/ui/context-menu.tsx | 386 +-- ui/src/components/ui/dialog.tsx | 227 +- ui/src/components/ui/dropdown-menu.tsx | 411 ++-- ui/src/components/ui/input.tsx | 38 +- ui/src/components/ui/resizable.tsx | 67 +- ui/src/components/ui/scroll-area.tsx | 85 +- ui/src/components/ui/select.tsx | 297 +-- ui/src/components/ui/sheet.tsx | 232 +- ui/src/components/ui/sonner.tsx | 40 + ui/src/components/ui/switch.tsx | 44 +- ui/src/components/ui/table.tsx | 185 +- ui/src/components/ui/tabs.tsx | 134 +- ui/src/components/ui/textarea.tsx | 12 +- ui/src/components/ui/toast.tsx | 128 - ui/src/components/ui/toaster-provider.tsx | 70 +- ui/src/components/ui/tooltip.tsx | 69 +- ui/src/lib/kalam-client.ts | 1 - 59 files changed, 3746 insertions(+), 2241 deletions(-) create mode 100644 link/sdks/typescript/orm/src/query-normalize.ts create mode 100644 link/sdks/typescript/orm/tests/sql-normalize.test.mjs create mode 100644 ui/eslint.config.js create mode 100644 ui/src/components/ui/sonner.tsx delete mode 100644 ui/src/components/ui/toast.tsx diff --git a/.config/nextest.toml b/.config/nextest.toml index 9016789f5..1004ab396 100644 --- a/.config/nextest.toml +++ b/.config/nextest.toml @@ -8,6 +8,7 @@ test-threads = 15 # other, while still allowing unrelated tests to use the remaining default # concurrency budget. stateful-heavy = { max-threads = 1 } +proxied-reconnect = { max-threads = 2 } [[profile.default.overrides]] filter = 'test(test_scenario_08_subscription_reconnect)' @@ -85,7 +86,7 @@ test-group = "stateful-heavy" [[profile.default.overrides]] filter = 'test(test_large_initial_snapshot_survives_repeated_outages)' -test-group = "stateful-heavy" +test-group = "proxied-reconnect" [[profile.default.overrides]] filter = 'test(test_latency_spike_during_initial_snapshot_recovers)' @@ -97,7 +98,7 @@ test-group = "stateful-heavy" [[profile.default.overrides]] filter = 'test(test_loading_snapshot_with_live_writes_resumes_without_duplicate_rows)' -test-group = "stateful-heavy" +test-group = "proxied-reconnect" [[profile.default.overrides]] filter = 'test(test_proxy_three_subscriptions_resume_after_server_bounce)' diff --git a/.github/workflows/orm.yml b/.github/workflows/orm.yml index c1ddfb8c7..ca176f321 100644 --- a/.github/workflows/orm.yml +++ b/.github/workflows/orm.yml @@ -88,5 +88,7 @@ jobs: - name: Run integration tests working-directory: link/sdks/typescript/orm env: + KALAMDB_TEST_URL: http://localhost:8088 + KALAMDB_TEST_USER: admin KALAMDB_TEST_PASSWORD: testpass123 run: node --test tests/driver.test.mjs tests/generate.test.mjs tests/cli.test.mjs tests/live.test.mjs diff --git a/.github/workflows/sdks.yml b/.github/workflows/sdks.yml index 76218762e..394ceb433 100644 --- a/.github/workflows/sdks.yml +++ b/.github/workflows/sdks.yml @@ -191,7 +191,7 @@ jobs: chmod +x ./kalamdb-server echo "SDK test source: release-binary" - - name: Run TypeScript SDK tests + - name: Run TypeScript client, consumer, and ORM npm package tests id: run_typescript_tests continue-on-error: true shell: bash @@ -207,6 +207,19 @@ jobs: set -euo pipefail ./scripts/test-typescript-sdk-release.sh + - name: Verify TypeScript npm package test coverage + if: always() + shell: bash + run: | + set -euo pipefail + output="ts-sdk-test-output.txt" + for package in client consumer orm; do + if ! grep -q "Running @kalamdb/${package} tests" "$output"; then + echo "Missing @kalamdb/${package} npm package test run in ${output}" >&2 + exit 1 + fi + done + - name: Parse TypeScript SDK test counts if: always() id: parse_typescript_badge diff --git a/backend/crates/kalamdb-api/src/ui/embedded.rs b/backend/crates/kalamdb-api/src/ui/embedded.rs index 6a883ceef..09020f32c 100644 --- a/backend/crates/kalamdb-api/src/ui/embedded.rs +++ b/backend/crates/kalamdb-api/src/ui/embedded.rs @@ -7,6 +7,8 @@ //! 1. Run `npm run build` in the `ui/` directory //! 2. Rebuild the server with `cargo build` +use std::borrow::Cow; + use actix_web::{web, HttpRequest, HttpResponse}; use log::debug; use rust_embed::Embed; @@ -22,6 +24,13 @@ use super::UiRuntimeConfig; #[exclude = "kalam_client_bg.wasm"] struct UiAssets; +fn embedded_asset_body(data: Cow<'static, [u8]>) -> web::Bytes { + match data { + Cow::Borrowed(bytes) => web::Bytes::from_static(bytes), + Cow::Owned(bytes) => web::Bytes::from(bytes), + } +} + /// Serve embedded UI assets /// /// Handles requests to /ui/* and serves the appropriate static file. @@ -43,7 +52,7 @@ pub async fn serve_embedded_ui(req: HttpRequest) -> HttpResponse { debug!("[embedded_ui] Found file: {} (mime: {})", path, mime_type); - return HttpResponse::Ok().content_type(mime_type).body(content.data.into_owned()); + return HttpResponse::Ok().content_type(mime_type).body(embedded_asset_body(content.data)); } debug!("[embedded_ui] File not found: {}, falling back to index.html", path); @@ -53,7 +62,7 @@ pub async fn serve_embedded_ui(req: HttpRequest) -> HttpResponse { if let Some(index) = UiAssets::get("index.html") { return HttpResponse::Ok() .content_type("text/html; charset=utf-8") - .body(index.data.into_owned()); + .body(embedded_asset_body(index.data)); } // No UI built - show helpful message diff --git a/backend/crates/kalamdb-api/src/ws/runtime.rs b/backend/crates/kalamdb-api/src/ws/runtime.rs index dc4fb4397..4616abb44 100644 --- a/backend/crates/kalamdb-api/src/ws/runtime.rs +++ b/backend/crates/kalamdb-api/src/ws/runtime.rs @@ -113,14 +113,12 @@ pub(super) async fn run_websocket( msg = msg_stream.next() => { match msg { Some(Ok(Message::Ping(bytes))) => { - record_activity_now(); connection_state.update_heartbeat(); if session.pong(&bytes).await.is_err() { break; } } Some(Ok(Message::Pong(_))) => { - record_activity_now(); connection_state.update_heartbeat(); } Some(Ok(Message::Text(text))) => { diff --git a/backend/crates/kalamdb-commons/benches/snowflake_generator.rs b/backend/crates/kalamdb-commons/benches/snowflake_generator.rs index 99796e013..fa227e9b0 100644 --- a/backend/crates/kalamdb-commons/benches/snowflake_generator.rs +++ b/backend/crates/kalamdb-commons/benches/snowflake_generator.rs @@ -1,13 +1,14 @@ use std::{ hint::black_box, - sync::{atomic::{AtomicU64, Ordering}, Arc}, + sync::{ + atomic::{AtomicU64, Ordering}, + Arc, + }, thread, time::{Duration, SystemTime, UNIX_EPOCH}, }; -use criterion::{ - criterion_group, criterion_main, BatchSize, BenchmarkId, Criterion, Throughput, -}; +use criterion::{criterion_group, criterion_main, BatchSize, BenchmarkId, Criterion, Throughput}; use kalamdb_commons::ids::SnowflakeGenerator; use parking_lot::Mutex; @@ -160,13 +161,17 @@ fn bench_batch_generation(c: &mut Criterion) { for batch_size in [32_usize, 256, 1024] { group.throughput(Throughput::Elements(batch_size as u64)); - group.bench_with_input(BenchmarkId::new("optimized", batch_size), &batch_size, |b, &size| { - b.iter_batched( - || SnowflakeGenerator::new(1), - |generator| black_box(generator.next_ids(size).expect("optimized next_ids")), - BatchSize::SmallInput, - ); - }); + group.bench_with_input( + BenchmarkId::new("optimized", batch_size), + &batch_size, + |b, &size| { + b.iter_batched( + || SnowflakeGenerator::new(1), + |generator| black_box(generator.next_ids(size).expect("optimized next_ids")), + BatchSize::SmallInput, + ); + }, + ); group.bench_with_input(BenchmarkId::new("legacy", batch_size), &batch_size, |b, &size| { b.iter_batched( @@ -180,71 +185,121 @@ fn bench_batch_generation(c: &mut Criterion) { group.finish(); } +fn bench_mapped_batch_generation(c: &mut Criterion) { + let mut group = c.benchmark_group("snowflake_mapped_batch_generation"); + + for batch_size in [256_usize, 1024] { + group.throughput(Throughput::Elements(batch_size as u64)); + + group.bench_with_input( + BenchmarkId::new("optimized_mapped", batch_size), + &batch_size, + |b, &size| { + b.iter_batched( + || SnowflakeGenerator::new(1), + |generator| { + black_box( + generator + .next_ids_mapped(size, |id| id.wrapping_mul(31)) + .expect("optimized next_ids_mapped"), + ) + }, + BatchSize::SmallInput, + ); + }, + ); + + group.bench_with_input( + BenchmarkId::new("legacy_then_map", batch_size), + &batch_size, + |b, &size| { + b.iter_batched( + || LegacySnowflakeGenerator::new(1), + |generator| { + let ids = generator.next_ids(size).expect("legacy next_ids"); + black_box(ids.into_iter().map(|id| id.wrapping_mul(31)).collect::>()) + }, + BatchSize::SmallInput, + ); + }, + ); + } + + group.finish(); +} + fn bench_concurrent_single_generation(c: &mut Criterion) { let mut group = c.benchmark_group("snowflake_concurrent_single_generation"); let thread_count = 8; let ids_per_thread = 1_000; group.throughput(Throughput::Elements((thread_count * ids_per_thread) as u64)); - group.bench_function(BenchmarkId::new("optimized", format!("{}x{}", thread_count, ids_per_thread)), |b| { - b.iter(|| { - let generator = Arc::new(SnowflakeGenerator::new(1)); - let duplicates = Arc::new(AtomicU64::new(0)); - thread::scope(|scope| { - let mut handles = Vec::with_capacity(thread_count); - for _ in 0..thread_count { - let generator = Arc::clone(&generator); - let duplicates = Arc::clone(&duplicates); - handles.push(scope.spawn(move || { - let mut prev = None; - for _ in 0..ids_per_thread { - let next = generator.next_id().expect("optimized concurrent next_id"); - if let Some(prev) = prev { - if next <= prev { - duplicates.fetch_add(1, Ordering::Relaxed); + group.bench_function( + BenchmarkId::new("optimized", format!("{}x{}", thread_count, ids_per_thread)), + |b| { + b.iter(|| { + let generator = Arc::new(SnowflakeGenerator::new(1)); + let duplicates = Arc::new(AtomicU64::new(0)); + thread::scope(|scope| { + let mut handles = Vec::with_capacity(thread_count); + for _ in 0..thread_count { + let generator = Arc::clone(&generator); + let duplicates = Arc::clone(&duplicates); + handles.push(scope.spawn(move || { + let mut prev = None; + for _ in 0..ids_per_thread { + let next = + generator.next_id().expect("optimized concurrent next_id"); + if let Some(prev) = prev { + if next <= prev { + duplicates.fetch_add(1, Ordering::Relaxed); + } } + prev = Some(next); } - prev = Some(next); - } - })); - } - for handle in handles { - handle.join().expect("optimized thread join"); - } + })); + } + for handle in handles { + handle.join().expect("optimized thread join"); + } + }); + assert_eq!(duplicates.load(Ordering::Relaxed), 0); }); - assert_eq!(duplicates.load(Ordering::Relaxed), 0); - }); - }); - - group.bench_function(BenchmarkId::new("legacy", format!("{}x{}", thread_count, ids_per_thread)), |b| { - b.iter(|| { - let generator = Arc::new(LegacySnowflakeGenerator::new(1)); - let duplicates = Arc::new(AtomicU64::new(0)); - thread::scope(|scope| { - let mut handles = Vec::with_capacity(thread_count); - for _ in 0..thread_count { - let generator = Arc::clone(&generator); - let duplicates = Arc::clone(&duplicates); - handles.push(scope.spawn(move || { - let mut prev = None; - for _ in 0..ids_per_thread { - let next = generator.next_id().expect("legacy concurrent next_id"); - if let Some(prev) = prev { - if next <= prev { - duplicates.fetch_add(1, Ordering::Relaxed); + }, + ); + + group.bench_function( + BenchmarkId::new("legacy", format!("{}x{}", thread_count, ids_per_thread)), + |b| { + b.iter(|| { + let generator = Arc::new(LegacySnowflakeGenerator::new(1)); + let duplicates = Arc::new(AtomicU64::new(0)); + thread::scope(|scope| { + let mut handles = Vec::with_capacity(thread_count); + for _ in 0..thread_count { + let generator = Arc::clone(&generator); + let duplicates = Arc::clone(&duplicates); + handles.push(scope.spawn(move || { + let mut prev = None; + for _ in 0..ids_per_thread { + let next = generator.next_id().expect("legacy concurrent next_id"); + if let Some(prev) = prev { + if next <= prev { + duplicates.fetch_add(1, Ordering::Relaxed); + } } + prev = Some(next); } - prev = Some(next); - } - })); - } - for handle in handles { - handle.join().expect("legacy thread join"); - } + })); + } + for handle in handles { + handle.join().expect("legacy thread join"); + } + }); + assert_eq!(duplicates.load(Ordering::Relaxed), 0); }); - assert_eq!(duplicates.load(Ordering::Relaxed), 0); - }); - }); + }, + ); group.finish(); } @@ -252,6 +307,6 @@ fn bench_concurrent_single_generation(c: &mut Criterion) { criterion_group!( name = benches; config = Criterion::default().sample_size(20).warm_up_time(Duration::from_millis(500)); - targets = bench_single_generation, bench_batch_generation, bench_concurrent_single_generation + targets = bench_single_generation, bench_batch_generation, bench_mapped_batch_generation, bench_concurrent_single_generation ); criterion_main!(benches); diff --git a/backend/crates/kalamdb-commons/src/ids/snowflake.rs b/backend/crates/kalamdb-commons/src/ids/snowflake.rs index 0496657b8..5875414b1 100644 --- a/backend/crates/kalamdb-commons/src/ids/snowflake.rs +++ b/backend/crates/kalamdb-commons/src/ids/snowflake.rs @@ -34,8 +34,8 @@ impl SnowflakeGenerator { pub const DEFAULT_EPOCH: u64 = 1704067200000; const TIMESTAMP_SHIFT: u32 = 22; + const SEQUENCE_BITS: u32 = 12; - const SEQUENCE_BITS: u32 = 12; /// Maximum worker ID pub const MAX_WORKER_ID: u16 = 1023; @@ -159,15 +159,28 @@ impl SnowflakeGenerator { /// Vector of unique, time-ordered Snowflake IDs #[inline] pub fn next_ids(&self, count: usize) -> Result, String> { + self.next_ids_mapped(count, |id| id) + } + + /// Generate multiple Snowflake IDs and map them into the caller's target type. + /// + /// This keeps the same single-lock batch reservation as `next_ids()` while + /// avoiding an intermediate `Vec` for wrappers such as `SeqId`. + #[inline] + pub fn next_ids_mapped(&self, count: usize, mut map: F) -> Result, String> + where + F: FnMut(i64) -> T, + { if count == 0 { return Ok(Vec::new()); } let mut state = self.state.lock(); let mut ids = Vec::with_capacity(count); + let mut generated = 0usize; - while ids.len() < count { - let remaining = count - ids.len(); + while generated < count { + let remaining = count - generated; let mut timestamp = self.reconcile_timestamp(state.last_timestamp)?; let (start_sequence, chunk_len) = if timestamp == state.last_timestamp { @@ -190,7 +203,8 @@ impl SnowflakeGenerator { }; state.last_timestamp = timestamp; - self.append_chunk_ids(&mut ids, timestamp, start_sequence, chunk_len); + self.append_chunk_ids(&mut ids, timestamp, start_sequence, chunk_len, &mut map); + generated += chunk_len; } Ok(ids) @@ -220,15 +234,21 @@ impl SnowflakeGenerator { (((timestamp - self.epoch) << Self::TIMESTAMP_SHIFT) | self.worker_bits | sequence) as i64 } - fn append_chunk_ids( + #[inline] + fn append_chunk_ids( &self, - ids: &mut Vec, + ids: &mut Vec, timestamp: u64, start_sequence: u64, chunk_len: usize, - ) { - for offset in 0..chunk_len { - ids.push(self.compose_id(timestamp, start_sequence + offset as u64)); + map: &mut F, + ) where + F: FnMut(i64) -> T, + { + let mut id = self.compose_id(timestamp, start_sequence); + for _ in 0..chunk_len { + ids.push(map(id)); + id += 1; } } } @@ -244,6 +264,7 @@ mod tests { use std::collections::HashSet; use super::*; + use crate::ids::SeqId; #[test] fn test_snowflake_generation() { @@ -439,6 +460,15 @@ mod tests { assert!(ids.is_empty()); } + #[test] + fn test_batch_generation_mapped() { + let gen = SnowflakeGenerator::new(1); + let ids = gen.next_ids_mapped(16, SeqId::new).unwrap(); + + assert_eq!(ids.len(), 16); + assert!(ids.windows(2).all(|pair| pair[0] < pair[1])); + } + #[test] fn test_batch_vs_single_equivalence() { // Batch generation should produce same type of IDs as single generation diff --git a/backend/crates/kalamdb-jobs/src/health_monitor.rs b/backend/crates/kalamdb-jobs/src/health_monitor.rs index 7257346f4..7f8b71546 100644 --- a/backend/crates/kalamdb-jobs/src/health_monitor.rs +++ b/backend/crates/kalamdb-jobs/src/health_monitor.rs @@ -22,7 +22,7 @@ impl HealthMonitor { let active_subscriptions = app_context.connection_registry().subscription_count(); let ws_sessions = get_websocket_session_count(); - if active_connections > 0 || active_subscriptions > 0 || ws_sessions > 0 { + if active_subscriptions > 0 { return; } @@ -39,7 +39,9 @@ impl HealthMonitor { } } - app_context.connection_registry().trim_idle_capacity(); + if active_connections == 0 && ws_sessions == 0 { + app_context.connection_registry().trim_idle_capacity(); + } kalamdb_observability::force_allocator_collection(true); record_activity_now(); @@ -49,6 +51,13 @@ impl HealthMonitor { cleared_plan_cache, idle_for, ); + } else if active_connections > 0 || ws_sessions > 0 { + log::debug!( + "Idle trim forced allocator collection after {:?} idle with {} connections and {} ws sessions", + idle_for, + active_connections, + ws_sessions, + ); } else { log::debug!("Idle trim forced allocator collection after {:?} idle", idle_for); } diff --git a/backend/crates/kalamdb-live/src/helpers/initial_data.rs b/backend/crates/kalamdb-live/src/helpers/initial_data.rs index b7c92be26..18b112f41 100644 --- a/backend/crates/kalamdb-live/src/helpers/initial_data.rs +++ b/backend/crates/kalamdb-live/src/helpers/initial_data.rs @@ -287,7 +287,9 @@ impl InitialDataFetcher { .execute_for_batches(&sql, user_id, role, ReadContext::Internal) .await?; - let mut rows_with_seq = materialize_initial_rows(batches, has_commit_seq, limit + 1).await?; + let mut rows_with_seq = + materialize_initial_rows(batches, has_commit_seq, limit + 1).await?; + sort_initial_rows(&mut rows_with_seq, has_commit_seq, &options); // Determine has_more and slice to limit let total_fetched = rows_with_seq.len(); @@ -563,10 +565,7 @@ fn materialize_initial_rows_sync( })?; let commit_seq_array = if has_commit_seq { let commit_idx = schema.index_of(SystemColumnNames::COMMIT_SEQ).map_err(|_| { - LiveError::Other(format!( - "Result missing {} column", - SystemColumnNames::COMMIT_SEQ - )) + LiveError::Other(format!("Result missing {} column", SystemColumnNames::COMMIT_SEQ)) })?; Some(batch.column(commit_idx)) } else { @@ -607,6 +606,28 @@ fn materialize_initial_rows_sync( Ok(rows_with_seq) } +fn sort_initial_rows( + rows_with_seq: &mut [(SeqId, Option, Row)], + has_commit_seq: bool, + options: &InitialDataOptions, +) { + if has_commit_seq && options.since_commit_seq.is_some() { + if options.fetch_last { + rows_with_seq.sort_unstable_by(|left, right| { + right.1.cmp(&left.1).then_with(|| right.0.cmp(&left.0)) + }); + } else { + rows_with_seq.sort_unstable_by(|left, right| { + left.1.cmp(&right.1).then_with(|| left.0.cmp(&right.0)) + }); + } + } else if options.fetch_last { + rows_with_seq.sort_unstable_by(|left, right| right.0.cmp(&left.0)); + } else { + rows_with_seq.sort_unstable_by(|left, right| left.0.cmp(&right.0)); + } +} + #[cfg(test)] mod tests { use std::sync::{ @@ -784,6 +805,61 @@ mod tests { assert!(options.include_deleted); } + fn test_row(id: &str) -> Row { + let mut values = BTreeMap::new(); + values.insert("id".to_string(), ScalarValue::Utf8(Some(id.to_string()))); + Row::new(values) + } + + #[test] + fn sort_initial_rows_orders_seq_before_truncation() { + let options = InitialDataOptions::batch(Some(SeqId::from(8)), Some(SeqId::from(30)), 3); + let mut rows = vec![ + (SeqId::from(10), None, test_row("seed-10")), + (SeqId::from(11), None, test_row("seed-11")), + (SeqId::from(12), None, test_row("seed-12")), + (SeqId::from(9), None, test_row("seed-9")), + ]; + + sort_initial_rows(&mut rows, false, &options); + rows.truncate(options.limit); + + let ids: Vec<_> = rows + .iter() + .map(|(_, _, row)| match row.values.get("id") { + Some(ScalarValue::Utf8(Some(id))) => id.as_str(), + _ => "", + }) + .collect(); + + assert_eq!(ids, vec!["seed-9", "seed-10", "seed-11"]); + } + + #[test] + fn sort_initial_rows_orders_commit_seq_window() { + let options = InitialDataOptions::batch(Some(SeqId::from(8)), Some(SeqId::from(30)), 3) + .with_commit_range(Some(4), Some(9)); + let mut rows = vec![ + (SeqId::from(12), Some(6), test_row("c6-s12")), + (SeqId::from(10), Some(5), test_row("c5-s10")), + (SeqId::from(11), Some(5), test_row("c5-s11")), + (SeqId::from(9), Some(5), test_row("c5-s9")), + ]; + + sort_initial_rows(&mut rows, true, &options); + rows.truncate(options.limit); + + let ids: Vec<_> = rows + .iter() + .map(|(_, _, row)| match row.values.get("id") { + Some(ScalarValue::Utf8(Some(id))) => id.as_str(), + _ => "", + }) + .collect(); + + assert_eq!(ids, vec!["c5-s9", "c5-s10", "c5-s11"]); + } + #[tokio::test] async fn snapshot_boundary_uses_local_max_seq_query() { let fetcher = InitialDataFetcher::new(Arc::new(EmptySchemaLookup)); @@ -996,9 +1072,7 @@ mod tests { ) .expect("record batch"); - let rows = materialize_initial_rows(vec![batch], true, 3) - .await - .expect("materialized rows"); + let rows = materialize_initial_rows(vec![batch], true, 3).await.expect("materialized rows"); assert_eq!(rows.len(), 2); assert_eq!(rows[0].0, SeqId::from(100)); @@ -1010,7 +1084,7 @@ mod tests { } #[tokio::test] - async fn fetch_initial_data_preserves_executor_row_order() { + async fn fetch_initial_data_returns_rows_in_seq_order() { let schema = Arc::new(Schema::new(vec![ Field::new("id", DataType::Int64, false), Field::new(SystemColumnNames::SEQ, DataType::Int64, false), @@ -1061,7 +1135,7 @@ mod tests { }) .collect(); - assert_eq!(ids, vec![2, 1]); + assert_eq!(ids, vec![1, 2]); } #[tokio::test] diff --git a/backend/crates/kalamdb-raft/src/error.rs b/backend/crates/kalamdb-raft/src/error.rs index a79b91b18..1160db307 100644 --- a/backend/crates/kalamdb-raft/src/error.rs +++ b/backend/crates/kalamdb-raft/src/error.rs @@ -52,14 +52,15 @@ pub enum RaftError { #[error("Command timed out after {0:?}")] Timeout(std::time::Duration), - /// Replication timeout - command committed but not all nodes applied + /// Raft progress timeout. #[error( - "Replication timeout for group {group}: committed at {committed_log_id} but not all nodes \ - applied within {timeout_ms}ms" + "Raft progress timeout for group {group}: {detail} (target={committed_log_id}, \ + timeout={timeout_ms}ms)" )] ReplicationTimeout { group: String, committed_log_id: String, + detail: String, timeout_ms: u64, }, @@ -182,6 +183,7 @@ mod tests { assert!(RaftError::ReplicationTimeout { group: "g1".to_string(), committed_log_id: "1-100".to_string(), + detail: "local apply barrier did not reach the required read point".to_string(), timeout_ms: 5000, } .is_retryable()); @@ -227,6 +229,7 @@ mod tests { let err = RaftError::ReplicationTimeout { group: "meta".to_string(), committed_log_id: "1-250".to_string(), + detail: "learner 2 did not catch up to the leader".to_string(), timeout_ms: 3000, }; let msg = format!("{}", err); @@ -255,6 +258,7 @@ mod tests { RaftError::ReplicationTimeout { group: "g".to_string(), committed_log_id: "1".to_string(), + detail: "local apply barrier did not reach the required read point".to_string(), timeout_ms: 100, }, RaftError::Shutdown, diff --git a/backend/crates/kalamdb-raft/src/manager/raft_group.rs b/backend/crates/kalamdb-raft/src/manager/raft_group.rs index b929d9a6a..811e77ec6 100644 --- a/backend/crates/kalamdb-raft/src/manager/raft_group.rs +++ b/backend/crates/kalamdb-raft/src/manager/raft_group.rs @@ -136,6 +136,30 @@ impl RaftGroup { self.storage.get_last_applied() } + /// Reconcile in-memory state-machine progress with persisted last_applied. + pub fn reconcile_state_machine_progress(&self) -> Option<(u64, u64)> { + self.storage.reconcile_state_machine_progress() + } + + fn local_apply_timeout( + &self, + applied_index: u64, + committed_index: u64, + snapshot_index: u64, + timeout: Duration, + ) -> RaftError { + RaftError::ReplicationTimeout { + group: self.group_id.to_string(), + committed_log_id: committed_index.max(snapshot_index).to_string(), + detail: format!( + "local apply barrier did not reach the required read point: applied={}, \ + committed={}, snapshot={}", + applied_index, committed_index, snapshot_index + ), + timeout_ms: timeout.as_millis() as u64, + } + } + /// Wait until this node has applied every log entry already known locally. pub async fn wait_for_local_apply_barrier(&self, timeout: Duration) -> Result { let metrics = @@ -158,22 +182,24 @@ impl RaftGroup { let elapsed = start.elapsed(); if elapsed >= timeout { - return Err(RaftError::ReplicationTimeout { - group: self.group_id.to_string(), - committed_log_id: target_index.to_string(), - timeout_ms: timeout.as_millis() as u64, - }); + return Err(self.local_apply_timeout( + applied_index, + committed_index, + snapshot_index, + timeout, + )); } match tokio::time::timeout(timeout - elapsed, applied_rx.changed()).await { Ok(Ok(())) => {}, Ok(Err(_)) => break, Err(_) => { - return Err(RaftError::ReplicationTimeout { - group: self.group_id.to_string(), - committed_log_id: target_index.to_string(), - timeout_ms: timeout.as_millis() as u64, - }); + return Err(self.local_apply_timeout( + applied_index, + committed_index, + snapshot_index, + timeout, + )); }, } } @@ -188,11 +214,12 @@ impl RaftGroup { } if start.elapsed() > timeout { - return Err(RaftError::ReplicationTimeout { - group: self.group_id.to_string(), - committed_log_id: target_index.to_string(), - timeout_ms: timeout.as_millis() as u64, - }); + return Err(self.local_apply_timeout( + applied_index, + committed_index, + snapshot_index, + timeout, + )); } tokio::time::sleep(poll_interval).await; @@ -372,6 +399,7 @@ impl RaftGroup { return Err(RaftError::ReplicationTimeout { group: self.group_id.to_string(), committed_log_id: "catchup".to_string(), + detail: format!("learner {} did not catch up to the leader", node_id), timeout_ms: timeout.as_millis() as u64, }); } diff --git a/backend/crates/kalamdb-raft/src/manager/raft_manager.rs b/backend/crates/kalamdb-raft/src/manager/raft_manager.rs index 1eff16ce9..0851827f4 100644 --- a/backend/crates/kalamdb-raft/src/manager/raft_manager.rs +++ b/backend/crates/kalamdb-raft/src/manager/raft_manager.rs @@ -1446,7 +1446,7 @@ impl RaftManager { ); } - /// Restore all state machines from their persisted snapshots + /// Restore all state machines from their persisted snapshots and progress metadata. /// /// This should be called AFTER all appliers are set. It restores the state machines' /// internal state from persisted snapshots to ensure idempotency checks work correctly @@ -1457,12 +1457,16 @@ impl RaftManager { pub async fn restore_state_machines_from_snapshots(&self) -> Result<(), RaftError> { let start = std::time::Instant::now(); let mut restored_count = 0; + let mut reconciled_count = 0; // Restore meta state machine if self.meta.has_snapshot() { self.meta.restore_state_machine_from_snapshot().await?; restored_count += 1; } + if self.meta.reconcile_state_machine_progress().is_some() { + reconciled_count += 1; + } // Restore user data state machines for shard in &self.user_data_shards { @@ -1470,6 +1474,9 @@ impl RaftManager { shard.restore_state_machine_from_snapshot().await?; restored_count += 1; } + if shard.reconcile_state_machine_progress().is_some() { + reconciled_count += 1; + } } // Restore shared data state machines @@ -1478,12 +1485,17 @@ impl RaftManager { shard.restore_state_machine_from_snapshot().await?; restored_count += 1; } + if shard.reconcile_state_machine_progress().is_some() { + reconciled_count += 1; + } } - if restored_count > 0 { + if restored_count > 0 || reconciled_count > 0 { log::info!( - "RaftManager: Restored {} state machines from snapshots in {:.2}ms", + "RaftManager: Restart recovery loaded {} in-memory state-machine snapshot(s) and \ + advanced {} apply watermark(s) from persisted last_applied in {:.2}ms", restored_count, + reconciled_count, start.elapsed().as_secs_f64() * 1000.0 ); } diff --git a/backend/crates/kalamdb-raft/src/state_machine/meta.rs b/backend/crates/kalamdb-raft/src/state_machine/meta.rs index 91d2d7ae9..b85bdff0d 100644 --- a/backend/crates/kalamdb-raft/src/state_machine/meta.rs +++ b/backend/crates/kalamdb-raft/src/state_machine/meta.rs @@ -623,7 +623,8 @@ impl KalamStateMachine for MetaStateMachine { self.publish_last_applied(snapshot.last_applied_index); log::info!( - "MetaStateMachine: Restored snapshot at index {} term {}", + "MetaStateMachine: Loaded in-memory metadata tracker from snapshot \ + (applied={}, term={})", snapshot.last_applied_index, snapshot.last_applied_term ); diff --git a/backend/crates/kalamdb-raft/src/state_machine/shared_data.rs b/backend/crates/kalamdb-raft/src/state_machine/shared_data.rs index 481a807af..3d29a72a1 100644 --- a/backend/crates/kalamdb-raft/src/state_machine/shared_data.rs +++ b/backend/crates/kalamdb-raft/src/state_machine/shared_data.rs @@ -539,8 +539,8 @@ impl KalamStateMachine for SharedDataStateMachine { self.publish_last_applied(snapshot.last_applied_index); log::info!( - "SharedDataStateMachine[{}]: Restored from snapshot at index {}, term {}, {} pending \ - commands", + "SharedDataStateMachine[{}]: Loaded in-memory shared-shard tracker from snapshot \ + (applied={}, term={}, pending_meta_waiters={})", self.shard, snapshot.last_applied_index, snapshot.last_applied_term, diff --git a/backend/crates/kalamdb-raft/src/state_machine/user_data.rs b/backend/crates/kalamdb-raft/src/state_machine/user_data.rs index 282355706..b369477e4 100644 --- a/backend/crates/kalamdb-raft/src/state_machine/user_data.rs +++ b/backend/crates/kalamdb-raft/src/state_machine/user_data.rs @@ -513,8 +513,8 @@ impl KalamStateMachine for UserDataStateMachine { self.publish_last_applied(snapshot.last_applied_index); log::info!( - "UserDataStateMachine[{}]: Restored from snapshot at index {}, term {}, {} pending \ - commands", + "UserDataStateMachine[{}]: Loaded in-memory user-shard tracker from snapshot \ + (applied={}, term={}, pending_meta_waiters={})", self.shard, snapshot.last_applied_index, snapshot.last_applied_term, diff --git a/backend/crates/kalamdb-raft/src/storage/raft_store.rs b/backend/crates/kalamdb-raft/src/storage/raft_store.rs index 06e2dbc36..408c89ad4 100644 --- a/backend/crates/kalamdb-raft/src/storage/raft_store.rs +++ b/backend/crates/kalamdb-raft/src/storage/raft_store.rs @@ -381,6 +381,8 @@ impl KalamRaftStorage { /// before the restart. pub async fn restore_state_machine_from_snapshot(&self) -> Result<(), crate::RaftError> { let start = std::time::Instant::now(); + let persisted_last_applied = *self.last_applied.read(); + let persisted_committed = *self.committed.read(); let snapshot_data = { let guard = self.current_snapshot.read(); guard.as_ref().map(|s| Arc::clone(&s.data)) @@ -408,23 +410,40 @@ impl KalamRaftStorage { let restore_ms = restore_start.elapsed().as_secs_f64() * 1000.0; log::info!( - "KalamRaftStorage[{}]: Restored state machine from snapshot \ - (last_applied_index={}, last_applied_term={}) - deserialize: {:.2}ms, restore: \ - {:.2}ms, total: {:.2}ms", + "KalamRaftStorage[{}]: Restart recovery loaded the in-memory state-machine \ + tracker from snapshot (snapshot_applied={}/{}, persisted_last_applied={}, \ + persisted_committed={}, deserialize={:.2}ms, restore={:.2}ms, total={:.2}ms)", self.group_id, sm_data.state_applied_index, sm_data.state_applied_term, + persisted_last_applied + .map(|id| id.index.to_string()) + .unwrap_or_else(|| "none".to_string()), + persisted_committed + .map(|id| id.index.to_string()) + .unwrap_or_else(|| "none".to_string()), deserialize_ms, restore_ms, start.elapsed().as_secs_f64() * 1000.0 ); } else { log::debug!( - "KalamRaftStorage[{}]: No snapshot to restore state machine from", + "KalamRaftStorage[{}]: No persisted snapshot for in-memory state-machine \ + restore; restart will rely on persisted last_applied/log state", self.group_id ); } + if let Some((from_index, to_index)) = self.reconcile_state_machine_progress() { + log::info!( + "KalamRaftStorage[{}]: Restart recovery advanced the in-memory apply watermark \ + from {} to {} using persisted last_applied metadata", + self.group_id, + from_index, + to_index + ); + } + Ok(()) } @@ -433,6 +452,21 @@ impl KalamRaftStorage { self.current_snapshot.read().is_some() } + /// Reconcile the in-memory state machine watermark with persisted progress. + pub fn reconcile_state_machine_progress(&self) -> Option<(u64, u64)> { + let last_applied = (*self.last_applied.read())?; + let current_index = self.state_machine.last_applied_index(); + + if last_applied.index <= current_index { + return None; + } + + self.state_machine + .mark_applied_index(last_applied.index, last_applied.leader_id.term); + + Some((current_index, last_applied.index)) + } + /// Get the last applied log ID from storage /// /// This is used to determine if the cluster has already been initialized @@ -543,6 +577,28 @@ impl KalamRaftStorage { }, } } + + fn persist_last_applied_log_id(&self, log_id: LogId) -> Result<(), StorageError> { + if let Some(store) = &self.persistent_store { + store + .save_last_applied(Some(RaftLogId { + term: log_id.leader_id.term, + index: log_id.index, + })) + .map_err(|e| StorageIOError::write(&e))?; + } + + Ok(()) + } + + fn commit_last_applied_log_id(&self, log_id: LogId) -> Result<(), StorageError> { + { + let mut last = self.last_applied.write(); + *last = Some(log_id); + } + + self.persist_last_applied_log_id(log_id) + } } /// Log reader implementation that shares access to the storage @@ -889,15 +945,10 @@ impl RaftStorage let index = log_id.index; let term = log_id.leader_id.term; - // Update last applied - { - let mut last = self.last_applied.write(); - *last = Some(log_id); - } - match &entry.payload { EntryPayload::Blank => { self.state_machine.mark_applied_index(index, term); + self.commit_last_applied_log_id(log_id)?; results.push(Vec::new()); }, EntryPayload::Normal(data) => { @@ -908,19 +959,29 @@ impl RaftStorage match sm.apply(index, term, data).await { Ok(apply_result) => match apply_result { crate::state_machine::ApplyResult::Ok(response_data) => { + self.commit_last_applied_log_id(log_id)?; results.push(response_data); }, crate::state_machine::ApplyResult::NoOp => { + self.commit_last_applied_log_id(log_id)?; results.push(Vec::new()); }, crate::state_machine::ApplyResult::Error(e) => { - log::error!("State machine apply error at index {}: {}", index, e); - results.push(Vec::new()); + let message = + format!("state machine apply error at index {}: {}", index, e); + log::error!("{}", message); + return Err( + StorageIOError::write(&std::io::Error::other(message)).into() + ); }, }, Err(e) => { - log::error!("State machine apply failed at index {}: {:?}", index, e); - results.push(Vec::new()); + let message = + format!("state machine apply failed at index {}: {:?}", index, e); + log::error!("{}", message); + return Err( + StorageIOError::write(&std::io::Error::other(message)).into() + ); }, } }, @@ -937,25 +998,12 @@ impl RaftStorage } } self.state_machine.mark_applied_index(index, term); + self.commit_last_applied_log_id(log_id)?; results.push(Vec::new()); }, } } - // Persist last_applied after processing all entries in this batch - // This is CRITICAL for crash recovery - without this, logs will be replayed on restart - if let Some(last_log_id) = entries.last().map(|e| e.log_id) { - if let Some(store) = &self.persistent_store { - let raft_log_id = RaftLogId { - term: last_log_id.leader_id.term, - index: last_log_id.index, - }; - if let Err(e) = store.save_last_applied(Some(raft_log_id)) { - log::error!("Failed to persist last_applied: {:?}", e); - } - } - } - Ok(results) } @@ -1266,6 +1314,84 @@ mod tests { } } + #[derive(Debug)] + struct ProgressOnlyStateMachine { + apply_calls: Arc, + last_applied_index: AtomicU64, + last_applied_term: AtomicU64, + } + + impl ProgressOnlyStateMachine { + fn new(apply_calls: Arc) -> Self { + Self { + apply_calls, + last_applied_index: AtomicU64::new(0), + last_applied_term: AtomicU64::new(0), + } + } + } + + #[async_trait] + impl KalamStateMachine for ProgressOnlyStateMachine { + fn group_id(&self) -> GroupId { + GroupId::Meta + } + + async fn apply( + &self, + index: u64, + term: u64, + _command: &[u8], + ) -> Result { + if index <= self.last_applied_index.load(Ordering::Acquire) { + return Ok(ApplyResult::NoOp); + } + + self.apply_calls.fetch_add(1, Ordering::Relaxed); + self.last_applied_index.store(index, Ordering::Release); + self.last_applied_term.store(term, Ordering::Release); + + Ok(ApplyResult::ok()) + } + + fn last_applied_index(&self) -> u64 { + self.last_applied_index.load(Ordering::Acquire) + } + + fn last_applied_term(&self) -> u64 { + self.last_applied_term.load(Ordering::Acquire) + } + + fn mark_applied_index(&self, index: u64, term: u64) { + let last_applied = self.last_applied_index.load(Ordering::Acquire); + if index <= last_applied { + return; + } + + self.last_applied_index.store(index, Ordering::Release); + self.last_applied_term.store(term, Ordering::Release); + } + + async fn snapshot(&self) -> Result { + Ok(StateMachineSnapshot::new( + self.group_id(), + self.last_applied_index(), + self.last_applied_term(), + Vec::new(), + )) + } + + async fn restore(&self, snapshot: StateMachineSnapshot) -> Result<(), RaftError> { + self.last_applied_index.store(snapshot.last_applied_index, Ordering::Release); + self.last_applied_term.store(snapshot.last_applied_term, Ordering::Release); + Ok(()) + } + + fn approximate_size(&self) -> usize { + 0 + } + } + #[tokio::test] async fn test_snapshot_build_and_install_restores_state() { let state = std::sync::Arc::new(AtomicU64::new(0)); @@ -1333,6 +1459,26 @@ mod tests { assert_eq!(last_applied, snapshot_meta.last_log_id); } + #[tokio::test] + async fn test_apply_failure_does_not_advance_last_applied() { + let state = Arc::new(AtomicU64::new(0)); + let sm = TestStateMachine::new(state); + let storage = Arc::new(KalamRaftStorage::new(GroupId::Meta, sm)); + let mut storage = storage; + + let entries = vec![Entry { + log_id: LogId::new(openraft::CommittedLeaderId::new(1, 1), 1), + payload: EntryPayload::Normal(vec![1, 2, 3]), + }]; + + let result = storage.apply_to_state_machine(&entries).await; + assert!(result.is_err()); + + let (last_applied, _) = storage.last_applied_state().await.unwrap(); + assert!(last_applied.is_none()); + assert_eq!(storage.state_machine().last_applied_index(), 0); + } + // ======================================================================== // Persistent Storage Tests // ======================================================================== @@ -1733,6 +1879,104 @@ mod tests { } } + #[tokio::test] + async fn test_restore_state_machine_reconciles_progress_beyond_snapshot() { + let backend = create_test_backend(); + let apply_calls = Arc::new(AtomicUsize::new(0)); + + { + let sm = ProgressOnlyStateMachine::new(apply_calls.clone()); + let storage = KalamRaftStorage::new_persistent( + GroupId::Meta, + sm, + backend.clone(), + test_snapshots_dir(), + ) + .unwrap(); + let storage = Arc::new(storage); + + let first_entries = vec![ + Entry { + log_id: LogId::new(openraft::CommittedLeaderId::new(1, 1), 1), + payload: EntryPayload::Normal(Vec::new()), + }, + Entry { + log_id: LogId::new(openraft::CommittedLeaderId::new(1, 1), 2), + payload: EntryPayload::Normal(Vec::new()), + }, + ]; + let mut storage_clone = storage.clone(); + storage_clone.apply_to_state_machine(&first_entries).await.unwrap(); + + let mut builder = storage_clone.get_snapshot_builder().await; + builder.build_snapshot().await.unwrap(); + + let tail_entries = vec![ + Entry { + log_id: LogId::new(openraft::CommittedLeaderId::new(1, 1), 3), + payload: EntryPayload::Normal(Vec::new()), + }, + Entry { + log_id: LogId::new(openraft::CommittedLeaderId::new(1, 1), 4), + payload: EntryPayload::Normal(Vec::new()), + }, + ]; + storage_clone.apply_to_state_machine(&tail_entries).await.unwrap(); + } + + apply_calls.store(0, Ordering::Release); + + let restored_sm = ProgressOnlyStateMachine::new(apply_calls.clone()); + let storage = KalamRaftStorage::new_persistent( + GroupId::Meta, + restored_sm, + backend, + test_snapshots_dir(), + ) + .unwrap(); + + storage.restore_state_machine_from_snapshot().await.unwrap(); + + assert_eq!(storage.state_machine().last_applied_index(), 4); + assert_eq!(apply_calls.load(Ordering::Acquire), 0); + } + + #[tokio::test] + async fn test_reconcile_state_machine_progress_without_snapshot() { + let backend = create_test_backend(); + + { + let sm = ProgressOnlyStateMachine::new(Arc::new(AtomicUsize::new(0))); + let storage = KalamRaftStorage::new_persistent( + GroupId::Meta, + sm, + backend.clone(), + test_snapshots_dir(), + ) + .unwrap(); + let mut storage = Arc::new(storage); + + let entries = vec![Entry { + log_id: LogId::new(openraft::CommittedLeaderId::new(1, 1), 2), + payload: EntryPayload::Normal(Vec::new()), + }]; + storage.apply_to_state_machine(&entries).await.unwrap(); + } + + let restored_sm = ProgressOnlyStateMachine::new(Arc::new(AtomicUsize::new(0))); + let storage = KalamRaftStorage::new_persistent( + GroupId::Meta, + restored_sm, + backend, + test_snapshots_dir(), + ) + .unwrap(); + + assert_eq!(storage.state_machine().last_applied_index(), 0); + assert_eq!(storage.reconcile_state_machine_progress(), Some((0, 2))); + assert_eq!(storage.state_machine().last_applied_index(), 2); + } + #[tokio::test] async fn test_different_groups_isolated_in_persistent_storage() { let backend = create_test_backend(); diff --git a/backend/crates/kalamdb-system/src/services/system_columns_service.rs b/backend/crates/kalamdb-system/src/services/system_columns_service.rs index cec5139b4..bafb3d89f 100644 --- a/backend/crates/kalamdb-system/src/services/system_columns_service.rs +++ b/backend/crates/kalamdb-system/src/services/system_columns_service.rs @@ -94,10 +94,9 @@ impl SystemColumnsService { /// # Errors /// Returns `SystemError::InvalidOperation` if clock moves backwards pub fn generate_seq_ids(&self, count: usize) -> Result, SystemError> { - let ids = self.snowflake_gen.next_ids(count).map_err(|e| { + self.snowflake_gen.next_ids_mapped(count, SeqId::new).map_err(|e| { SystemError::InvalidOperation(format!("Batch SeqId generation failed: {}", e)) - })?; - Ok(ids.into_iter().map(SeqId::new).collect()) + }) } /// Add system columns to a table definition diff --git a/docker/build/Dockerfile.prebuilt b/docker/build/Dockerfile.prebuilt index 72b81f437..995b2b891 100644 --- a/docker/build/Dockerfile.prebuilt +++ b/docker/build/Dockerfile.prebuilt @@ -9,7 +9,7 @@ RUN sed -i 's|data_path = "\./data"|data_path = "/data"|g' /runtime/config/serve # ---------- Stage 2: binary prep ---------- -FROM debian:bookworm-slim AS binary-prep +FROM ubuntu:24.04 AS binary-prep RUN apt-get update -o Acquire::Retries=3 && \ DEBIAN_FRONTEND=noninteractive apt-get install -y --no-install-recommends \ @@ -26,7 +26,7 @@ RUN chmod 755 /staged/usr/local/bin/* && \ # ---------- Stage 3: final runtime ---------- -FROM debian:bookworm-slim +FROM ubuntu:24.04 ARG OCI_IMAGE_TITLE="KalamDB" ARG OCI_IMAGE_DESCRIPTION="KalamDB database server" diff --git a/link/kalam-client/tests/proxied/loading_resume_with_live_writes.rs b/link/kalam-client/tests/proxied/loading_resume_with_live_writes.rs index 800e9d3fb..1a81efedb 100644 --- a/link/kalam-client/tests/proxied/loading_resume_with_live_writes.rs +++ b/link/kalam-client/tests/proxied/loading_resume_with_live_writes.rs @@ -16,7 +16,6 @@ fn observe_loading_event( max_seq: &mut Option, strict_from: Option, initial_batch_count: &mut u32, - highest_batch_num: &mut u32, context: &str, ) { if let Some(from) = strict_from { @@ -27,9 +26,8 @@ fn observe_loading_event( *max_seq = Some(max_seq.map_or(seq, |prev| prev.max(seq))); } - if let ChangeEvent::InitialDataBatch { batch_control, .. } = event { + if let ChangeEvent::InitialDataBatch { .. } = event { *initial_batch_count += 1; - *highest_batch_num = (*highest_batch_num).max(batch_control.batch_num); } let Some(rows) = change_event_rows(event) else { @@ -135,7 +133,6 @@ async fn test_loading_snapshot_with_live_writes_resumes_without_duplicate_rows() let mut seen_seqs = HashSet::::new(); let mut delivered_seq = None; let mut initial_batch_count = 0u32; - let mut highest_batch_num = 0u32; let mut inserted_during_loading = false; for _ in 0..20 { @@ -152,7 +149,6 @@ async fn test_loading_snapshot_with_live_writes_resumes_without_duplicate_rows() &mut delivered_seq, None, &mut initial_batch_count, - &mut highest_batch_num, "loading snapshot before outage", ); @@ -213,7 +209,6 @@ async fn test_loading_snapshot_with_live_writes_resumes_without_duplicate_rows() &mut delivered_seq, None, &mut initial_batch_count, - &mut highest_batch_num, "loading snapshot local tail", ), _ => break, @@ -292,7 +287,6 @@ async fn test_loading_snapshot_with_live_writes_resumes_without_duplicate_rows() &mut delivered_seq, Some(resume_from), &mut initial_batch_count, - &mut highest_batch_num, "loading snapshot resumed", ), Ok(Some(Err(e))) => panic!("loading subscription errored after reconnect: {}", e), @@ -331,11 +325,6 @@ async fn test_loading_snapshot_with_live_writes_resumes_without_duplicate_rows() "30 seed rows with batch size 3 should span at least 10 initial batches, got {}", initial_batch_count ); - assert!( - highest_batch_num >= 9, - "expected to observe at least batch 9, got {}", - highest_batch_num - ); assert_eq!( seen_ids.len(), 30 + 2 + 3 + 2, diff --git a/link/link-common/src/client/runtime.rs b/link/link-common/src/client/runtime.rs index 1a029dd2d..39637a25f 100644 --- a/link/link-common/src/client/runtime.rs +++ b/link/link-common/src/client/runtime.rs @@ -157,7 +157,8 @@ impl KalamLinkClient { }; // Lock released here ↑ - // Phase 2: Wait for the server Ready ack without the lock held. + // Phase 2: Wait for the server ack without the lock held. Initial + // snapshot batches continue through the returned subscription stream. if let Some((event_rx, result_rx, shared_control)) = pending { let (generation, resume_from) = result_rx.await.map_err(|_| { KalamLinkError::WebSocketError( diff --git a/link/link-common/src/connection/shared/reconnect.rs b/link/link-common/src/connection/shared/reconnect.rs index 2d9d18317..0ac4162b9 100644 --- a/link/link-common/src/connection/shared/reconnect.rs +++ b/link/link-common/src/connection/shared/reconnect.rs @@ -257,6 +257,8 @@ async fn handle_startup_timeouts( cache_entry_seq(seq_id_cache, id.as_str(), &entry); if let Some(result_tx) = entry.pending_result_tx.take() { let _ = result_tx.send(Err(KalamLinkError::TimeoutError(message))); + } else { + let _ = entry.event_tx.try_send(Err(KalamLinkError::TimeoutError(message))); } } } diff --git a/link/link-common/src/connection/shared/routing.rs b/link/link-common/src/connection/shared/routing.rs index f949cd733..4e3d65087 100644 --- a/link/link-common/src/connection/shared/routing.rs +++ b/link/link-common/src/connection/shared/routing.rs @@ -66,6 +66,8 @@ pub(super) async fn route_event( let event_time_ms = now_ms(); let auto_request_next_batch = matches!(event, ChangeEvent::InitialDataBatch { .. }); + let mut next_batch_last_seq = None; + let mut should_request_next_batch = false; if let Some(batch) = batch_envelope(&event) { if let Some(key) = matched_key.as_ref() { @@ -81,28 +83,36 @@ pub(super) async fn route_event( } } if auto_request_next_batch && batch.has_more { - let last_seq = matched_key + next_batch_last_seq = matched_key .as_ref() .and_then(|key| subs.get(key.as_str(&incoming_sub_id))) .and_then(|entry| entry.batch_seq_id.or(entry.last_seq_id)); - if let Err(error) = - send_next_batch_request_with_format(ws, &incoming_sub_id, last_seq, serialization) - .await - { - log::warn!("Failed to send NextBatch for {}: {}", incoming_sub_id, error); - } + should_request_next_batch = true; } } if let Some(key) = matched_key { let mut remove_after_send = false; + let mut delivered_event = false; let key_str = key.as_str(&incoming_sub_id); if let Some(entry) = subs.get_mut(key_str) { entry.last_event_time_ms = Some(event_time_ms); + let is_ack = matches!(event, ChangeEvent::Ack { .. }); let is_start_ready = subscription_start_ready(&event); match &event { + ChangeEvent::Ack { .. } => { + entry.reconnect_resubscribe_pending = false; + if let Some(result_tx) = entry.pending_result_tx.take() { + let _ = result_tx.send(Ok((entry.generation, entry.options.from))); + } + if is_start_ready { + clear_startup_deadline(entry); + } else if entry.is_loading { + refresh_startup_deadline(entry, timeouts); + } + }, _ if is_start_ready => { clear_startup_deadline(entry); if let Some(result_tx) = entry.pending_result_tx.take() { @@ -122,7 +132,7 @@ pub(super) async fn route_event( _ => {}, } - if !is_start_ready { + if !is_ack && !is_start_ready { if entry.is_loading { refresh_startup_deadline(entry, timeouts); } else if entry.reconnect_resubscribe_pending { @@ -130,8 +140,12 @@ pub(super) async fn route_event( } } - if !remove_after_send && entry.event_tx.send(Ok(event)).await.is_err() { - log::debug!("Subscription {} receiver dropped", incoming_sub_id); + if !remove_after_send { + if entry.event_tx.send(Ok(event)).await.is_err() { + log::debug!("Subscription {} receiver dropped", incoming_sub_id); + } else { + delivered_event = true; + } } } @@ -140,6 +154,19 @@ pub(super) async fn route_event( cache_entry_seq(seq_id_cache, key_str, &entry); } } + + if delivered_event && should_request_next_batch { + if let Err(error) = send_next_batch_request_with_format( + ws, + &incoming_sub_id, + next_batch_last_seq, + serialization, + ) + .await + { + log::warn!("Failed to send NextBatch for {}: {}", incoming_sub_id, error); + } + } } else { log::debug!("No subscription found for id: {}", incoming_sub_id); } diff --git a/link/link-common/src/subscription/checkpoint.rs b/link/link-common/src/subscription/checkpoint.rs index 9a191fd8a..7d78a9c17 100644 --- a/link/link-common/src/subscription/checkpoint.rs +++ b/link/link-common/src/subscription/checkpoint.rs @@ -42,7 +42,7 @@ pub(crate) fn subscription_start_ready(event: &ChangeEvent) -> bool { #[cfg(any(feature = "tokio-runtime", test))] pub(crate) fn event_progress(event: &ChangeEvent) -> Option { match event { - ChangeEvent::InitialDataBatch { rows, .. } if subscription_start_ready(event) => { + ChangeEvent::InitialDataBatch { rows, .. } => { let batch = batch_envelope(event); let seq_id = seq_tracking::extract_max_seq(rows) .or_else(|| batch.and_then(|batch| batch.last_seq_id))?; @@ -266,6 +266,25 @@ mod tests { ); } + #[test] + fn progress_marks_loading_initial_batch_without_advancing_resume() { + let mut control = batch_control(BatchStatus::LoadingBatch); + control.last_seq_id = Some(SeqId::from_i64(21)); + let event = ChangeEvent::InitialDataBatch { + subscription_id: "sub-1".to_string(), + rows: Vec::new(), + batch_control: control, + }; + + assert_eq!( + event_progress(&event), + Some(EventProgress { + seq_id: SeqId::from_i64(21), + advance_resume: false, + }) + ); + } + #[test] fn buffering_flushes_live_changes_after_ready_snapshot() { let mut event_queue = VecDeque::new(); diff --git a/link/link-common/src/subscription/manager.rs b/link/link-common/src/subscription/manager.rs index 5d72a980a..f74784dad 100644 --- a/link/link-common/src/subscription/manager.rs +++ b/link/link-common/src/subscription/manager.rs @@ -12,6 +12,7 @@ use crate::{ error::Result, models::ChangeEvent, seq_id::SeqId, + seq_tracking, subscription::{buffer_event, event_progress}, timeouts::KalamLinkTimeouts, }; @@ -83,11 +84,14 @@ impl SubscriptionManager { } } - async fn report_shared_progress(&self, event: &ChangeEvent) { - let Some(shared_control) = self.shared_control.as_ref() else { + async fn report_shared_progress(&mut self, event: &ChangeEvent) { + let Some(progress) = event_progress(event) else { return; }; - let Some(progress) = event_progress(event) else { + + seq_tracking::advance_seq(&mut self.resume_from, progress.seq_id); + + let Some(shared_control) = self.shared_control.as_ref() else { return; }; @@ -253,6 +257,40 @@ mod tests { drop(sub); } + #[tokio::test] + async fn test_consumed_initial_batch_advances_local_replay_filter() { + let mut sub = make_test_sub(); + let event = ChangeEvent::InitialDataBatch { + subscription_id: "unit-test-id".to_string(), + rows: vec![{ + let mut row = std::collections::HashMap::new(); + row.insert("id".to_string(), crate::models::KalamCellValue::text("seed")); + row.insert("_seq".to_string(), crate::models::KalamCellValue::text("10")); + row + }], + batch_control: crate::models::BatchControl { + batch_num: 0, + has_more: true, + status: crate::models::BatchStatus::Loading, + last_seq_id: Some(SeqId::from_i64(10)), + }, + }; + + sub.report_shared_progress(&event).await; + sub.apply_buffering(ChangeEvent::Insert { + subscription_id: "unit-test-id".to_string(), + rows: vec![{ + let mut row = std::collections::HashMap::new(); + row.insert("id".to_string(), crate::models::KalamCellValue::text("seed")); + row.insert("_seq".to_string(), crate::models::KalamCellValue::text("10")); + row + }], + }); + + assert!(sub.event_queue.is_empty()); + assert!(sub.buffered_changes.is_empty()); + } + #[tokio::test] async fn test_drop_inside_runtime_does_not_panic() { let sub = make_test_sub(); diff --git a/link/sdks/typescript/orm/README.md b/link/sdks/typescript/orm/README.md index b5d7e5abe..c300dda1f 100644 --- a/link/sdks/typescript/orm/README.md +++ b/link/sdks/typescript/orm/README.md @@ -15,6 +15,7 @@ npm i @kalamdb/client @kalamdb/orm drizzle-orm ```ts import { Auth, createClient } from '@kalamdb/client'; import { kalamDriver } from '@kalamdb/orm'; +import { drizzle } from 'drizzle-orm/pg-proxy'; import { messages } from './schema'; const client = createClient({ @@ -22,7 +23,7 @@ const client = createClient({ authProvider: async () => Auth.basic('admin', 'AdminPass123!'), }); -const db = kalamDriver(client); +const db = drizzle(kalamDriver(client)); const rows = await db.select().from(messages).limit(20); ``` @@ -49,6 +50,17 @@ export const docs = kTable.shared('app.docs', { `file()`, `bytes()`, and `embedding()` are KalamDB-specific Drizzle custom columns. `file()` maps values to `FileRef | null`, `bytes()` maps to `Uint8Array | null`, and `embedding()` maps to `number[] | null`. +Use the table-kind helpers when the table kind matters to live views or agents: + +```ts +kTable.shared('app.docs', columns); +kTable.user('app.messages', columns); +kTable.stream('app.events', columns); +kTable.system('system.users', columns); +``` + +Pass `{ systemColumns: true }` when your app needs typed `_seq`/`_deleted` fields for ordering, resume checks, or diagnostics. Streams only receive `_seq`; shared and user tables receive `_seq` and `_deleted`. + ## Generate `schema.ts` ```bash @@ -106,3 +118,25 @@ await stop(); ``` `liveTable()` and `subscribeTable()` reuse the same `@kalamdb/client` connection and normalize timestamp/date/time fields according to the Drizzle table definition. + +## Execute as a user + +Agents and service workers can compile a Drizzle builder and run it through KalamDB's `EXECUTE AS USER` path: + +```ts +import { executeAsUser } from '@kalamdb/orm'; + +await executeAsUser( + client, + db.insert(messages).values({ + room: 'main', + role: 'assistant', + author: 'KalamDB Copilot', + sender_username: 'alice', + content: 'Done.', + }), + 'alice', +); +``` + +Only pass a user id that your service account is authorized to impersonate. diff --git a/link/sdks/typescript/orm/package.json b/link/sdks/typescript/orm/package.json index eafc01797..1313d622d 100644 --- a/link/sdks/typescript/orm/package.json +++ b/link/sdks/typescript/orm/package.json @@ -37,7 +37,7 @@ "clean": "node -e \"const fs=require('fs');try{fs.rmSync('dist',{recursive:true,force:true})}catch{}\"", "build": "npm run clean && tsc", "build:orm": "npm run build", - "test": "npm run build && node --test tests/ktable.test.mjs tests/generate-unit.test.mjs tests/driver.test.mjs tests/filtering.test.mjs tests/agent-consumer.test.mjs tests/temporal-normalize.test.mjs tests/file-column.test.mjs tests/strip-defaults.test.mjs tests/generate.test.mjs tests/live.test.mjs tests/cli.test.mjs", + "test": "npm run build && node --test tests/ktable.test.mjs tests/generate-unit.test.mjs tests/driver.test.mjs tests/filtering.test.mjs tests/agent-consumer.test.mjs tests/temporal-normalize.test.mjs tests/file-column.test.mjs tests/strip-defaults.test.mjs tests/sql-normalize.test.mjs tests/generate.test.mjs tests/live.test.mjs tests/cli.test.mjs", "prepublishOnly": "npm run build" }, "peerDependencies": { diff --git a/link/sdks/typescript/orm/src/driver.ts b/link/sdks/typescript/orm/src/driver.ts index c5d5c9b26..8896d6bfd 100644 --- a/link/sdks/typescript/orm/src/driver.ts +++ b/link/sdks/typescript/orm/src/driver.ts @@ -1,5 +1,6 @@ import type { RemoteCallback } from 'drizzle-orm/pg-proxy'; import type { KalamDBClient } from '@kalamdb/client'; +import { stripQuotedIdentifiers } from './query-normalize.js'; type QueryClient = Pick; type ColumnNormalizer = (value: unknown) => unknown; @@ -148,7 +149,7 @@ export function stripDefaults(sql: string, params: unknown[]): { sql: string; pa export function kalamDriver(client: QueryClient): RemoteCallback { return async (sql, params, method) => { - let cleanSql = sql.replace(/"/g, ''); + let cleanSql = stripQuotedIdentifiers(sql); const stripped = stripDefaults(cleanSql, params); cleanSql = stripped.sql; diff --git a/link/sdks/typescript/orm/src/query-normalize.ts b/link/sdks/typescript/orm/src/query-normalize.ts new file mode 100644 index 000000000..d7a03ae4b --- /dev/null +++ b/link/sdks/typescript/orm/src/query-normalize.ts @@ -0,0 +1,35 @@ +export function stripQuotedIdentifiers(sql: string): string { + let normalized = ''; + let index = 0; + let inSingleQuotedString = false; + + while (index < sql.length) { + const char = sql[index]; + + if (char === "'") { + normalized += char; + if (inSingleQuotedString && sql[index + 1] === "'") { + normalized += sql[index + 1]; + index += 2; + continue; + } + inSingleQuotedString = !inSingleQuotedString; + index += 1; + continue; + } + + if (!inSingleQuotedString && char === '"') { + const end = sql.indexOf('"', index + 1); + if (end !== -1) { + normalized += sql.slice(index + 1, end); + index = end + 1; + continue; + } + } + + normalized += char; + index += 1; + } + + return normalized; +} diff --git a/link/sdks/typescript/orm/src/sql.ts b/link/sdks/typescript/orm/src/sql.ts index 53163d3a4..e34aff1b5 100644 --- a/link/sdks/typescript/orm/src/sql.ts +++ b/link/sdks/typescript/orm/src/sql.ts @@ -2,6 +2,7 @@ import type { KalamDBClient, QueryResponse, UserId } from '@kalamdb/client'; import type { SQLWrapper } from 'drizzle-orm'; import { PgDialect } from 'drizzle-orm/pg-core'; import { stripDefaults } from './driver.js'; +import { stripQuotedIdentifiers } from './query-normalize.js'; type ExecuteAsUserClient = Pick; @@ -27,7 +28,7 @@ function hasToSQL(value: SqlSource): value is QueryBuilderLike { } function normalizeSql(sql: string): string { - return sql.replace(/"/g, ''); + return stripQuotedIdentifiers(sql); } function normalizeCompiledQuery(compiled: CompiledQuery): CompiledQuery { diff --git a/link/sdks/typescript/orm/tests/helpers.mjs b/link/sdks/typescript/orm/tests/helpers.mjs index 342d66f39..e034f54a8 100644 --- a/link/sdks/typescript/orm/tests/helpers.mjs +++ b/link/sdks/typescript/orm/tests/helpers.mjs @@ -1,8 +1,8 @@ import { createClient, Auth } from '@kalamdb/client'; -export const URL = process.env.KALAMDB_TEST_URL || 'http://localhost:8088'; +export const URL = process.env.KALAMDB_TEST_URL || 'http://localhost:8080'; export const USER = process.env.KALAMDB_TEST_USER || 'admin'; -export const PASS = process.env.KALAMDB_TEST_PASSWORD; +export const PASS = process.env.KALAMDB_TEST_PASSWORD || 'kalamdb123'; export function requirePassword() { if (!PASS) { diff --git a/link/sdks/typescript/orm/tests/sql-normalize.test.mjs b/link/sdks/typescript/orm/tests/sql-normalize.test.mjs new file mode 100644 index 000000000..93c402e97 --- /dev/null +++ b/link/sdks/typescript/orm/tests/sql-normalize.test.mjs @@ -0,0 +1,18 @@ +import { describe, it } from 'node:test'; +import assert from 'node:assert/strict'; +import { sql } from 'drizzle-orm'; +import { stripQuotedIdentifiers } from '../dist/query-normalize.js'; +import { compileInlineQuery } from '../dist/sql.js'; + +describe('SQL normalization', () => { + it('strips quoted identifiers without changing string literals', () => { + const normalized = stripQuotedIdentifiers('SELECT "room" FROM "chat_demo"."messages" WHERE "content" = \'a"b\''); + assert.equal(normalized, 'SELECT room FROM chat_demo.messages WHERE content = \'a"b\''); + }); + + it('preserves escaped single quotes and double quotes inside inline parameters', () => { + const compiled = compileInlineQuery(sql`SELECT * FROM ${sql.raw('chat_demo.messages')} WHERE content = ${"a\"b and it's ok"}`); + assert.equal(compiled.sql, "SELECT * FROM chat_demo.messages WHERE content = 'a\"b and it''s ok'"); + assert.deepEqual(compiled.params, []); + }); +}); diff --git a/nextest.toml b/nextest.toml index 400bb8007..bb102736e 100644 --- a/nextest.toml +++ b/nextest.toml @@ -8,6 +8,7 @@ test-threads = 15 # other, while still allowing unrelated tests to use the remaining default # concurrency budget. stateful-heavy = { max-threads = 1 } +proxied-reconnect = { max-threads = 2 } [[profile.default.overrides]] filter = 'test(test_scenario_08_subscription_reconnect)' @@ -85,7 +86,7 @@ test-group = "stateful-heavy" [[profile.default.overrides]] filter = 'test(test_large_initial_snapshot_survives_repeated_outages)' -test-group = "stateful-heavy" +test-group = "proxied-reconnect" [[profile.default.overrides]] filter = 'test(test_latency_spike_during_initial_snapshot_recovers)' @@ -97,7 +98,7 @@ test-group = "stateful-heavy" [[profile.default.overrides]] filter = 'test(test_loading_snapshot_with_live_writes_resumes_without_duplicate_rows)' -test-group = "stateful-heavy" +test-group = "proxied-reconnect" [[profile.default.overrides]] filter = 'test(test_proxy_three_subscriptions_resume_after_server_bounce)' diff --git a/ui/components.json b/ui/components.json index bda2c3e79..485a36563 100644 --- a/ui/components.json +++ b/ui/components.json @@ -1,6 +1,5 @@ { "$schema": "https://ui.shadcn.com/schema.json", - "version": "3.6.1", "style": "radix-mira", "rsc": false, "tsx": true, @@ -19,9 +18,7 @@ "hooks": "@/hooks" }, "iconLibrary": "lucide", - "theme": { - "extend": "lime", - "radius": 0.3, - "font": "Outfit" - } + "menuColor": "default", + "menuAccent": "subtle", + "rtl": false } diff --git a/ui/eslint.config.js b/ui/eslint.config.js new file mode 100644 index 000000000..8840793b0 --- /dev/null +++ b/ui/eslint.config.js @@ -0,0 +1,40 @@ +import js from "@eslint/js"; +import tsParser from "@typescript-eslint/parser"; +import tsPlugin from "@typescript-eslint/eslint-plugin"; +import globals from "globals"; + +export default [ + { + ignores: ["dist/**", "node_modules/**"], + }, + { + files: ["**/*.{js,mjs,cjs}"], + ...js.configs.recommended, + languageOptions: { + globals: { + ...globals.browser, + ...globals.node, + }, + }, + }, + { + files: ["**/*.{ts,tsx}"], + languageOptions: { + parser: tsParser, + parserOptions: { + ecmaVersion: "latest", + sourceType: "module", + ecmaFeatures: { + jsx: true, + }, + }, + globals: { + ...globals.browser, + ...globals.node, + }, + }, + plugins: { + "@typescript-eslint": tsPlugin, + }, + }, +]; \ No newline at end of file diff --git a/ui/package-lock.json b/ui/package-lock.json index a55bda1d6..6d42ddd9a 100644 --- a/ui/package-lock.json +++ b/ui/package-lock.json @@ -12,19 +12,6 @@ "@kalamdb/client": "file:../link/sdks/typescript/client", "@kalamdb/orm": "file:../link/sdks/typescript/orm", "@monaco-editor/react": "^4.7.0", - "@radix-ui/react-context-menu": "^2.2.16", - "@radix-ui/react-dialog": "^1.1.15", - "@radix-ui/react-dropdown-menu": "^2.1.16", - "@radix-ui/react-icons": "^1.3.2", - "@radix-ui/react-label": "^2.1.8", - "@radix-ui/react-scroll-area": "^1.2.10", - "@radix-ui/react-select": "^2.2.6", - "@radix-ui/react-separator": "^1.1.8", - "@radix-ui/react-slot": "^1.2.4", - "@radix-ui/react-switch": "^1.2.6", - "@radix-ui/react-tabs": "^1.1.13", - "@radix-ui/react-toast": "^1.2.15", - "@radix-ui/react-tooltip": "^1.2.8", "@reduxjs/toolkit": "^2.11.2", "@tailwindcss/postcss": "^4.2.4", "@tanstack/react-table": "^8.21.3", @@ -32,37 +19,41 @@ "clsx": "^2.1.1", "drizzle-orm": "^0.45.2", "fast-deep-equal": "^3.1.3", - "lucide-react": "^1.7.0", + "lucide-react": "^1.14.0", + "radix-ui": "^1.4.3", "react": "^19.2.5", "react-dom": "^19.2.5", - "react-hook-form": "^7.72.1", + "react-hook-form": "^7.75.0", "react-redux": "^9.2.0", - "react-resizable-panels": "^4.9.0", - "react-router-dom": "^7.14.1", + "react-resizable-panels": "^4.11.0", + "react-router-dom": "^7.14.2", "recharts": "^3.8.1", + "sonner": "^2.0.7", "tailwind-merge": "^3.5.0", "tailwindcss-animate": "^1.0.7", - "zod": "^4.3.6" + "zod": "^4.4.3" }, "devDependencies": { + "@eslint/js": "^10.0.1", "@testing-library/jest-dom": "^6.9.1", "@testing-library/react": "^16.3.2", - "@types/node": "^25.5.2", + "@types/node": "^25.6.0", "@types/react": "^19.2.14", "@types/react-dom": "^19.2.3", - "@typescript-eslint/eslint-plugin": "^8.58.0", - "@typescript-eslint/parser": "^8.58.0", + "@typescript-eslint/eslint-plugin": "^8.59.2", + "@typescript-eslint/parser": "^8.59.2", "@vitejs/plugin-react": "^6.0.1", - "autoprefixer": "^10.4.27", - "eslint": "^9.39.4", - "eslint-plugin-react-hooks": "^7.0.1", + "autoprefixer": "^10.5.0", + "eslint": "^10.3.0", + "eslint-plugin-react-hooks": "^7.1.1", "eslint-plugin-react-refresh": "^0.5.2", - "jsdom": "^29.0.1", - "postcss": "^8.5.8", - "tailwindcss": "^4.2.2", - "typescript": "^6.0.2", - "vite": "^8.0.8", - "vitest": "^4.1.4" + "globals": "^17.6.0", + "jsdom": "^29.1.1", + "postcss": "^8.5.14", + "tailwindcss": "^4.2.4", + "typescript": "^6.0.3", + "vite": "^8.0.10", + "vitest": "^4.1.5" } }, "../link/sdks/typescript": { @@ -72,7 +63,7 @@ }, "../link/sdks/typescript/client": { "name": "@kalamdb/client", - "version": "0.4.2-rc.3", + "version": "0.4.3-rc.4", "license": "Apache-2.0", "dependencies": { "ws": "^8.20.0" @@ -87,13 +78,14 @@ }, "../link/sdks/typescript/orm": { "name": "@kalamdb/orm", - "version": "0.4.2-rc.3", + "version": "0.4.3-rc.5", "license": "Apache-2.0", "bin": { "kalamdb-orm": "dist/cli.js" }, "devDependencies": { "@kalamdb/client": "file:../client", + "@kalamdb/consumer": "file:../consumer", "@types/node": "^25.5.2", "drizzle-orm": "^0.41.0", "typescript": "^5.8.0" @@ -122,53 +114,53 @@ } }, "node_modules/@asamuzakjp/css-color": { - "version": "5.0.1", + "version": "5.1.11", + "resolved": "https://registry.npmjs.org/@asamuzakjp/css-color/-/css-color-5.1.11.tgz", + "integrity": "sha512-KVw6qIiCTUQhByfTd78h2yD1/00waTmm9uy/R7Ck/ctUyAPj+AEDLkQIdJW0T8+qGgj3j5bpNKK7Q3G+LedJWg==", "dev": true, "license": "MIT", "dependencies": { - "@csstools/css-calc": "^3.1.1", - "@csstools/css-color-parser": "^4.0.2", + "@asamuzakjp/generational-cache": "^1.0.1", + "@csstools/css-calc": "^3.2.0", + "@csstools/css-color-parser": "^4.1.0", "@csstools/css-parser-algorithms": "^4.0.0", - "@csstools/css-tokenizer": "^4.0.0", - "lru-cache": "^11.2.6" + "@csstools/css-tokenizer": "^4.0.0" }, "engines": { "node": "^20.19.0 || ^22.12.0 || >=24.0.0" } }, - "node_modules/@asamuzakjp/css-color/node_modules/lru-cache": { - "version": "11.2.7", - "dev": true, - "license": "BlueOak-1.0.0", - "engines": { - "node": "20 || >=22" - } - }, "node_modules/@asamuzakjp/dom-selector": { - "version": "7.0.3", + "version": "7.1.1", + "resolved": "https://registry.npmjs.org/@asamuzakjp/dom-selector/-/dom-selector-7.1.1.tgz", + "integrity": "sha512-67RZDnYRc8H/8MLDgQCDE//zoqVFwajkepHZgmXrbwybzXOEwOWGPYGmALYl9J2DOLfFPPs6kKCqmbzV895hTQ==", "dev": true, "license": "MIT", "dependencies": { + "@asamuzakjp/generational-cache": "^1.0.1", "@asamuzakjp/nwsapi": "^2.3.9", "bidi-js": "^1.0.3", "css-tree": "^3.2.1", - "is-potential-custom-element-name": "^1.0.1", - "lru-cache": "^11.2.7" + "is-potential-custom-element-name": "^1.0.1" }, "engines": { "node": "^20.19.0 || ^22.12.0 || >=24.0.0" } }, - "node_modules/@asamuzakjp/dom-selector/node_modules/lru-cache": { - "version": "11.2.7", + "node_modules/@asamuzakjp/generational-cache": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/@asamuzakjp/generational-cache/-/generational-cache-1.0.1.tgz", + "integrity": "sha512-wajfB8KqzMCN2KGNFdLkReeHncd0AslUSrvHVvvYWuU8ghncRJoA50kT3zP9MVL0+9g4/67H+cdvBskj9THPzg==", "dev": true, - "license": "BlueOak-1.0.0", + "license": "MIT", "engines": { - "node": "20 || >=22" + "node": "^20.19.0 || ^22.12.0 || >=24.0.0" } }, "node_modules/@asamuzakjp/nwsapi": { "version": "2.3.9", + "resolved": "https://registry.npmjs.org/@asamuzakjp/nwsapi/-/nwsapi-2.3.9.tgz", + "integrity": "sha512-n8GuYSrI9bF7FFZ/SjhwevlHc8xaVlb/7HmHelnc/PZXBD2ZR49NnN9sMMuDdEGPeeRQ5d0hqlSlEpgCX3Wl0Q==", "dev": true, "license": "MIT" }, @@ -417,6 +409,8 @@ }, "node_modules/@csstools/color-helpers": { "version": "6.0.2", + "resolved": "https://registry.npmjs.org/@csstools/color-helpers/-/color-helpers-6.0.2.tgz", + "integrity": "sha512-LMGQLS9EuADloEFkcTBR3BwV/CGHV7zyDxVRtVDTwdI2Ca4it0CCVTT9wCkxSgokjE5Ho41hEPgb8OEUwoXr6Q==", "dev": true, "funding": [ { @@ -434,7 +428,9 @@ } }, "node_modules/@csstools/css-calc": { - "version": "3.1.1", + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/@csstools/css-calc/-/css-calc-3.2.0.tgz", + "integrity": "sha512-bR9e6o2BDB12jzN/gIbjHa5wLJ4UjD1CB9pM7ehlc0ddk6EBz+yYS1EV2MF55/HUxrHcB/hehAyt5vhsA3hx7w==", "dev": true, "funding": [ { @@ -456,7 +452,9 @@ } }, "node_modules/@csstools/css-color-parser": { - "version": "4.0.2", + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/@csstools/css-color-parser/-/css-color-parser-4.1.0.tgz", + "integrity": "sha512-U0KhLYmy2GVj6q4T3WaAe6NPuFYCPQoE3b0dRGxejWDgcPp8TP7S5rVdM5ZrFaqu4N67X8YaPBw14dQSYx3IyQ==", "dev": true, "funding": [ { @@ -471,7 +469,7 @@ "license": "MIT", "dependencies": { "@csstools/color-helpers": "^6.0.2", - "@csstools/css-calc": "^3.1.1" + "@csstools/css-calc": "^3.2.0" }, "engines": { "node": ">=20.19.0" @@ -483,6 +481,8 @@ }, "node_modules/@csstools/css-parser-algorithms": { "version": "4.0.0", + "resolved": "https://registry.npmjs.org/@csstools/css-parser-algorithms/-/css-parser-algorithms-4.0.0.tgz", + "integrity": "sha512-+B87qS7fIG3L5h3qwJ/IFbjoVoOe/bpOdh9hAjXbvx0o8ImEmUsGXN0inFOnk2ChCFgqkkGFQ+TpM5rbhkKe4w==", "dev": true, "funding": [ { @@ -503,7 +503,9 @@ } }, "node_modules/@csstools/css-syntax-patches-for-csstree": { - "version": "1.1.1", + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/@csstools/css-syntax-patches-for-csstree/-/css-syntax-patches-for-csstree-1.1.3.tgz", + "integrity": "sha512-SH60bMfrRCJF3morcdk57WklujF4Jr/EsQUzqkarfHXEFcAR1gg7fS/chAE922Sehgzc1/+Tz5H3Ypa1HiEKrg==", "dev": true, "funding": [ { @@ -527,6 +529,8 @@ }, "node_modules/@csstools/css-tokenizer": { "version": "4.0.0", + "resolved": "https://registry.npmjs.org/@csstools/css-tokenizer/-/css-tokenizer-4.0.0.tgz", + "integrity": "sha512-QxULHAm7cNu72w97JUNCBFODFaXpbDg+dP8b/oWFAZ2MTRppA3U00Y2L1HqaS4J6yBqxwa/Y3nMBaxVKbB/NsA==", "dev": true, "funding": [ { @@ -544,9 +548,9 @@ } }, "node_modules/@emnapi/core": { - "version": "1.9.2", - "resolved": "https://registry.npmjs.org/@emnapi/core/-/core-1.9.2.tgz", - "integrity": "sha512-UC+ZhH3XtczQYfOlu3lNEkdW/p4dsJ1r/bP7H8+rhao3TTTMO1ATq/4DdIi23XuGoFY+Cz0JmCbdVl0hz9jZcA==", + "version": "1.10.0", + "resolved": "https://registry.npmjs.org/@emnapi/core/-/core-1.10.0.tgz", + "integrity": "sha512-yq6OkJ4p82CAfPl0u9mQebQHKPJkY7WrIuk205cTYnYe+k2Z8YBh11FrbRG/H6ihirqcacOgl2BIO8oyMQLeXw==", "license": "MIT", "optional": true, "dependencies": { @@ -555,9 +559,9 @@ } }, "node_modules/@emnapi/runtime": { - "version": "1.9.2", - "resolved": "https://registry.npmjs.org/@emnapi/runtime/-/runtime-1.9.2.tgz", - "integrity": "sha512-3U4+MIWHImeyu1wnmVygh5WlgfYDtyf0k8AbLhMFxOipihf6nrWC4syIm/SwEeec0mNSafiiNnMJwbza/Is6Lw==", + "version": "1.10.0", + "resolved": "https://registry.npmjs.org/@emnapi/runtime/-/runtime-1.10.0.tgz", + "integrity": "sha512-ewvYlk86xUoGI0zQRNq/mC+16R1QeDlKQy21Ki3oSYXNgLb45GV1P6A0M+/s6nyCuNDqe5VpaY84BzXGwVbwFA==", "license": "MIT", "optional": true, "dependencies": { @@ -600,149 +604,89 @@ } }, "node_modules/@eslint/config-array": { - "version": "0.21.2", + "version": "0.23.5", + "resolved": "https://registry.npmjs.org/@eslint/config-array/-/config-array-0.23.5.tgz", + "integrity": "sha512-Y3kKLvC1dvTOT+oGlqNQ1XLqK6D1HU2YXPc52NmAlJZbMMWDzGYXMiPRJ8TYD39muD/OTjlZmNJ4ib7dvSrMBA==", "dev": true, "license": "Apache-2.0", "dependencies": { - "@eslint/object-schema": "^2.1.7", + "@eslint/object-schema": "^3.0.5", "debug": "^4.3.1", - "minimatch": "^3.1.5" - }, - "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" - } - }, - "node_modules/@eslint/config-array/node_modules/balanced-match": { - "version": "1.0.2", - "dev": true, - "license": "MIT" - }, - "node_modules/@eslint/config-array/node_modules/brace-expansion": { - "version": "1.1.12", - "dev": true, - "license": "MIT", - "dependencies": { - "balanced-match": "^1.0.0", - "concat-map": "0.0.1" - } - }, - "node_modules/@eslint/config-array/node_modules/minimatch": { - "version": "3.1.5", - "dev": true, - "license": "ISC", - "dependencies": { - "brace-expansion": "^1.1.7" + "minimatch": "^10.2.4" }, "engines": { - "node": "*" + "node": "^20.19.0 || ^22.13.0 || >=24" } }, "node_modules/@eslint/config-helpers": { - "version": "0.4.2", + "version": "0.5.5", + "resolved": "https://registry.npmjs.org/@eslint/config-helpers/-/config-helpers-0.5.5.tgz", + "integrity": "sha512-eIJYKTCECbP/nsKaaruF6LW967mtbQbsw4JTtSVkUQc9MneSkbrgPJAbKl9nWr0ZeowV8BfsarBmPpBzGelA2w==", "dev": true, "license": "Apache-2.0", "dependencies": { - "@eslint/core": "^0.17.0" + "@eslint/core": "^1.2.1" }, "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + "node": "^20.19.0 || ^22.13.0 || >=24" } }, "node_modules/@eslint/core": { - "version": "0.17.0", + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/@eslint/core/-/core-1.2.1.tgz", + "integrity": "sha512-MwcE1P+AZ4C6DWlpin/OmOA54mmIZ/+xZuJiQd4SyB29oAJjN30UW9wkKNptW2ctp4cEsvhlLY/CsQ1uoHDloQ==", "dev": true, "license": "Apache-2.0", "dependencies": { "@types/json-schema": "^7.0.15" }, "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" - } - }, - "node_modules/@eslint/eslintrc": { - "version": "3.3.5", - "dev": true, - "license": "MIT", - "dependencies": { - "ajv": "^6.14.0", - "debug": "^4.3.2", - "espree": "^10.0.1", - "globals": "^14.0.0", - "ignore": "^5.2.0", - "import-fresh": "^3.2.1", - "js-yaml": "^4.1.1", - "minimatch": "^3.1.5", - "strip-json-comments": "^3.1.1" - }, - "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" - }, - "funding": { - "url": "https://opencollective.com/eslint" - } - }, - "node_modules/@eslint/eslintrc/node_modules/balanced-match": { - "version": "1.0.2", - "dev": true, - "license": "MIT" - }, - "node_modules/@eslint/eslintrc/node_modules/brace-expansion": { - "version": "1.1.12", - "dev": true, - "license": "MIT", - "dependencies": { - "balanced-match": "^1.0.0", - "concat-map": "0.0.1" - } - }, - "node_modules/@eslint/eslintrc/node_modules/ignore": { - "version": "5.3.2", - "dev": true, - "license": "MIT", - "engines": { - "node": ">= 4" - } - }, - "node_modules/@eslint/eslintrc/node_modules/minimatch": { - "version": "3.1.5", - "dev": true, - "license": "ISC", - "dependencies": { - "brace-expansion": "^1.1.7" - }, - "engines": { - "node": "*" + "node": "^20.19.0 || ^22.13.0 || >=24" } }, "node_modules/@eslint/js": { - "version": "9.39.4", + "version": "10.0.1", + "resolved": "https://registry.npmjs.org/@eslint/js/-/js-10.0.1.tgz", + "integrity": "sha512-zeR9k5pd4gxjZ0abRoIaxdc7I3nDktoXZk2qOv9gCNWx3mVwEn32VRhyLaRsDiJjTs0xq/T8mfPtyuXu7GWBcA==", "dev": true, "license": "MIT", "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + "node": "^20.19.0 || ^22.13.0 || >=24" }, "funding": { "url": "https://eslint.org/donate" + }, + "peerDependencies": { + "eslint": "^10.0.0" + }, + "peerDependenciesMeta": { + "eslint": { + "optional": true + } } }, "node_modules/@eslint/object-schema": { - "version": "2.1.7", + "version": "3.0.5", + "resolved": "https://registry.npmjs.org/@eslint/object-schema/-/object-schema-3.0.5.tgz", + "integrity": "sha512-vqTaUEgxzm+YDSdElad6PiRoX4t8VGDjCtt05zn4nU810UIx/uNEV7/lZJ6KwFThKZOzOxzXy48da+No7HZaMw==", "dev": true, "license": "Apache-2.0", "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + "node": "^20.19.0 || ^22.13.0 || >=24" } }, "node_modules/@eslint/plugin-kit": { - "version": "0.4.1", + "version": "0.7.1", + "resolved": "https://registry.npmjs.org/@eslint/plugin-kit/-/plugin-kit-0.7.1.tgz", + "integrity": "sha512-rZAP3aVgB9ds9KOeUSL+zZ21hPmo8dh6fnIFwRQj5EAZl9gzR7wxYbYXYysAM8CTqGmUGyp2S4kUdV17MnGuWQ==", "dev": true, "license": "Apache-2.0", "dependencies": { - "@eslint/core": "^0.17.0", + "@eslint/core": "^1.2.1", "levn": "^0.4.1" }, "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + "node": "^20.19.0 || ^22.13.0 || >=24" } }, "node_modules/@exodus/bytes": { @@ -916,9 +860,9 @@ } }, "node_modules/@oxc-project/types": { - "version": "0.124.0", - "resolved": "https://registry.npmjs.org/@oxc-project/types/-/types-0.124.0.tgz", - "integrity": "sha512-VBFWMTBvHxS11Z5Lvlr3IWgrwhMTXV+Md+EQF0Xf60+wAdsGFTBx7X7K/hP4pi8N7dcm1RvcHwDxZ16Qx8keUg==", + "version": "0.127.0", + "resolved": "https://registry.npmjs.org/@oxc-project/types/-/types-0.127.0.tgz", + "integrity": "sha512-aIYXQBo4lCbO4z0R3FHeucQHpF46l2LbMdxRvqvuRuW2OxdnSkcng5B8+K12spgLDj93rtN3+J2Vac/TIO+ciQ==", "dev": true, "license": "MIT", "funding": { @@ -933,11 +877,13 @@ "version": "1.1.3", "license": "MIT" }, - "node_modules/@radix-ui/react-arrow": { + "node_modules/@radix-ui/react-accessible-icon": { "version": "1.1.7", + "resolved": "https://registry.npmjs.org/@radix-ui/react-accessible-icon/-/react-accessible-icon-1.1.7.tgz", + "integrity": "sha512-XM+E4WXl0OqUJFovy6GjmxxFyx9opfCAIUku4dlKRd5YEPqt4kALOkQOp0Of6reHuUkJuiPBEc5k0o4z4lTC8A==", "license": "MIT", "dependencies": { - "@radix-ui/react-primitive": "2.1.3" + "@radix-ui/react-visually-hidden": "1.2.3" }, "peerDependencies": { "@types/react": "*", @@ -954,14 +900,21 @@ } } }, - "node_modules/@radix-ui/react-collection": { - "version": "1.1.7", + "node_modules/@radix-ui/react-accordion": { + "version": "1.2.12", + "resolved": "https://registry.npmjs.org/@radix-ui/react-accordion/-/react-accordion-1.2.12.tgz", + "integrity": "sha512-T4nygeh9YE9dLRPhAHSeOZi7HBXo+0kYIPJXayZfvWOWA0+n3dESrZbjfDPUABkUNym6Hd+f2IR113To8D2GPA==", "license": "MIT", "dependencies": { + "@radix-ui/primitive": "1.1.3", + "@radix-ui/react-collapsible": "1.1.12", + "@radix-ui/react-collection": "1.1.7", "@radix-ui/react-compose-refs": "1.1.2", "@radix-ui/react-context": "1.1.2", + "@radix-ui/react-direction": "1.1.1", + "@radix-ui/react-id": "1.1.1", "@radix-ui/react-primitive": "2.1.3", - "@radix-ui/react-slot": "1.2.3" + "@radix-ui/react-use-controllable-state": "1.2.2" }, "peerDependencies": { "@types/react": "*", @@ -978,38 +931,42 @@ } } }, - "node_modules/@radix-ui/react-collection/node_modules/@radix-ui/react-slot": { - "version": "1.2.3", + "node_modules/@radix-ui/react-alert-dialog": { + "version": "1.1.15", + "resolved": "https://registry.npmjs.org/@radix-ui/react-alert-dialog/-/react-alert-dialog-1.1.15.tgz", + "integrity": "sha512-oTVLkEw5GpdRe29BqJ0LSDFWI3qu0vR1M0mUkOQWDIUnY/QIkLpgDMWuKxP94c2NAC2LGcgVhG1ImF3jkZ5wXw==", "license": "MIT", "dependencies": { - "@radix-ui/react-compose-refs": "1.1.2" + "@radix-ui/primitive": "1.1.3", + "@radix-ui/react-compose-refs": "1.1.2", + "@radix-ui/react-context": "1.1.2", + "@radix-ui/react-dialog": "1.1.15", + "@radix-ui/react-primitive": "2.1.3", + "@radix-ui/react-slot": "1.2.3" }, "peerDependencies": { "@types/react": "*", - "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "peerDependenciesMeta": { "@types/react": { "optional": true - } - } - }, - "node_modules/@radix-ui/react-compose-refs": { - "version": "1.1.2", - "license": "MIT", - "peerDependencies": { - "@types/react": "*", - "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" - }, - "peerDependenciesMeta": { - "@types/react": { + }, + "@types/react-dom": { "optional": true } } }, - "node_modules/@radix-ui/react-context": { - "version": "1.1.2", + "node_modules/@radix-ui/react-alert-dialog/node_modules/@radix-ui/react-slot": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/@radix-ui/react-slot/-/react-slot-1.2.3.tgz", + "integrity": "sha512-aeNmHnBxbi2St0au6VBVC7JXFlhLlOnvIIlePNniyUNAClzmtAUEY8/pBiK3iHjufOlwA+c20/8jngo7xcrg8A==", "license": "MIT", + "dependencies": { + "@radix-ui/react-compose-refs": "1.1.2" + }, "peerDependencies": { "@types/react": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" @@ -1020,16 +977,11 @@ } } }, - "node_modules/@radix-ui/react-context-menu": { - "version": "2.2.16", + "node_modules/@radix-ui/react-arrow": { + "version": "1.1.7", "license": "MIT", "dependencies": { - "@radix-ui/primitive": "1.1.3", - "@radix-ui/react-context": "1.1.2", - "@radix-ui/react-menu": "2.1.16", - "@radix-ui/react-primitive": "2.1.3", - "@radix-ui/react-use-callback-ref": "1.1.1", - "@radix-ui/react-use-controllable-state": "1.2.2" + "@radix-ui/react-primitive": "2.1.3" }, "peerDependencies": { "@types/react": "*", @@ -1046,24 +998,13 @@ } } }, - "node_modules/@radix-ui/react-dialog": { - "version": "1.1.15", + "node_modules/@radix-ui/react-aspect-ratio": { + "version": "1.1.7", + "resolved": "https://registry.npmjs.org/@radix-ui/react-aspect-ratio/-/react-aspect-ratio-1.1.7.tgz", + "integrity": "sha512-Yq6lvO9HQyPwev1onK1daHCHqXVLzPhSVjmsNjCa2Zcxy2f7uJD2itDtxknv6FzAKCwD1qQkeVDmX/cev13n/g==", "license": "MIT", "dependencies": { - "@radix-ui/primitive": "1.1.3", - "@radix-ui/react-compose-refs": "1.1.2", - "@radix-ui/react-context": "1.1.2", - "@radix-ui/react-dismissable-layer": "1.1.11", - "@radix-ui/react-focus-guards": "1.1.3", - "@radix-ui/react-focus-scope": "1.1.7", - "@radix-ui/react-id": "1.1.1", - "@radix-ui/react-portal": "1.1.9", - "@radix-ui/react-presence": "1.1.5", - "@radix-ui/react-primitive": "2.1.3", - "@radix-ui/react-slot": "1.2.3", - "@radix-ui/react-use-controllable-state": "1.2.2", - "aria-hidden": "^1.2.4", - "react-remove-scroll": "^2.6.3" + "@radix-ui/react-primitive": "2.1.3" }, "peerDependencies": { "@types/react": "*", @@ -1080,44 +1021,47 @@ } } }, - "node_modules/@radix-ui/react-dialog/node_modules/@radix-ui/react-slot": { - "version": "1.2.3", + "node_modules/@radix-ui/react-avatar": { + "version": "1.1.10", + "resolved": "https://registry.npmjs.org/@radix-ui/react-avatar/-/react-avatar-1.1.10.tgz", + "integrity": "sha512-V8piFfWapM5OmNCXTzVQY+E1rDa53zY+MQ4Y7356v4fFz6vqCyUtIz2rUD44ZEdwg78/jKmMJHj07+C/Z/rcog==", "license": "MIT", "dependencies": { - "@radix-ui/react-compose-refs": "1.1.2" + "@radix-ui/react-context": "1.1.2", + "@radix-ui/react-primitive": "2.1.3", + "@radix-ui/react-use-callback-ref": "1.1.1", + "@radix-ui/react-use-is-hydrated": "0.1.0", + "@radix-ui/react-use-layout-effect": "1.1.1" }, "peerDependencies": { "@types/react": "*", - "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "peerDependenciesMeta": { "@types/react": { "optional": true - } - } - }, - "node_modules/@radix-ui/react-direction": { - "version": "1.1.1", - "license": "MIT", - "peerDependencies": { - "@types/react": "*", - "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" - }, - "peerDependenciesMeta": { - "@types/react": { + }, + "@types/react-dom": { "optional": true } } }, - "node_modules/@radix-ui/react-dismissable-layer": { - "version": "1.1.11", + "node_modules/@radix-ui/react-checkbox": { + "version": "1.3.3", + "resolved": "https://registry.npmjs.org/@radix-ui/react-checkbox/-/react-checkbox-1.3.3.tgz", + "integrity": "sha512-wBbpv+NQftHDdG86Qc0pIyXk5IR3tM8Vd0nWLKDcX8nNn4nXFOFwsKuqw2okA/1D/mpaAkmuyndrPJTYDNZtFw==", "license": "MIT", "dependencies": { "@radix-ui/primitive": "1.1.3", "@radix-ui/react-compose-refs": "1.1.2", + "@radix-ui/react-context": "1.1.2", + "@radix-ui/react-presence": "1.1.5", "@radix-ui/react-primitive": "2.1.3", - "@radix-ui/react-use-callback-ref": "1.1.1", - "@radix-ui/react-use-escape-keydown": "1.1.1" + "@radix-ui/react-use-controllable-state": "1.2.2", + "@radix-ui/react-use-previous": "1.1.1", + "@radix-ui/react-use-size": "1.1.1" }, "peerDependencies": { "@types/react": "*", @@ -1134,17 +1078,20 @@ } } }, - "node_modules/@radix-ui/react-dropdown-menu": { - "version": "2.1.16", + "node_modules/@radix-ui/react-collapsible": { + "version": "1.1.12", + "resolved": "https://registry.npmjs.org/@radix-ui/react-collapsible/-/react-collapsible-1.1.12.tgz", + "integrity": "sha512-Uu+mSh4agx2ib1uIGPP4/CKNULyajb3p92LsVXmH2EHVMTfZWpll88XJ0j4W0z3f8NK1eYl1+Mf/szHPmcHzyA==", "license": "MIT", "dependencies": { "@radix-ui/primitive": "1.1.3", "@radix-ui/react-compose-refs": "1.1.2", "@radix-ui/react-context": "1.1.2", "@radix-ui/react-id": "1.1.1", - "@radix-ui/react-menu": "2.1.16", + "@radix-ui/react-presence": "1.1.5", "@radix-ui/react-primitive": "2.1.3", - "@radix-ui/react-use-controllable-state": "1.2.2" + "@radix-ui/react-use-controllable-state": "1.2.2", + "@radix-ui/react-use-layout-effect": "1.1.1" }, "peerDependencies": { "@types/react": "*", @@ -1161,26 +1108,14 @@ } } }, - "node_modules/@radix-ui/react-focus-guards": { - "version": "1.1.3", - "license": "MIT", - "peerDependencies": { - "@types/react": "*", - "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" - }, - "peerDependenciesMeta": { - "@types/react": { - "optional": true - } - } - }, - "node_modules/@radix-ui/react-focus-scope": { + "node_modules/@radix-ui/react-collection": { "version": "1.1.7", "license": "MIT", "dependencies": { "@radix-ui/react-compose-refs": "1.1.2", + "@radix-ui/react-context": "1.1.2", "@radix-ui/react-primitive": "2.1.3", - "@radix-ui/react-use-callback-ref": "1.1.1" + "@radix-ui/react-slot": "1.2.3" }, "peerDependencies": { "@types/react": "*", @@ -1197,18 +1132,11 @@ } } }, - "node_modules/@radix-ui/react-icons": { - "version": "1.3.2", - "license": "MIT", - "peerDependencies": { - "react": "^16.x || ^17.x || ^18.x || ^19.0.0 || ^19.0.0-rc" - } - }, - "node_modules/@radix-ui/react-id": { - "version": "1.1.1", + "node_modules/@radix-ui/react-collection/node_modules/@radix-ui/react-slot": { + "version": "1.2.3", "license": "MIT", "dependencies": { - "@radix-ui/react-use-layout-effect": "1.1.1" + "@radix-ui/react-compose-refs": "1.1.2" }, "peerDependencies": { "@types/react": "*", @@ -1220,32 +1148,413 @@ } } }, - "node_modules/@radix-ui/react-label": { - "version": "2.1.8", + "node_modules/@radix-ui/react-compose-refs": { + "version": "1.1.2", "license": "MIT", - "dependencies": { - "@radix-ui/react-primitive": "2.1.4" - }, "peerDependencies": { "@types/react": "*", - "@types/react-dom": "*", - "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", - "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "peerDependenciesMeta": { "@types/react": { "optional": true - }, - "@types/react-dom": { - "optional": true } } }, - "node_modules/@radix-ui/react-label/node_modules/@radix-ui/react-primitive": { - "version": "2.1.4", + "node_modules/@radix-ui/react-context": { + "version": "1.1.2", + "license": "MIT", + "peerDependencies": { + "@types/react": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-context-menu": { + "version": "2.2.16", + "license": "MIT", + "dependencies": { + "@radix-ui/primitive": "1.1.3", + "@radix-ui/react-context": "1.1.2", + "@radix-ui/react-menu": "2.1.16", + "@radix-ui/react-primitive": "2.1.3", + "@radix-ui/react-use-callback-ref": "1.1.1", + "@radix-ui/react-use-controllable-state": "1.2.2" + }, + "peerDependencies": { + "@types/react": "*", + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-dialog": { + "version": "1.1.15", + "license": "MIT", + "dependencies": { + "@radix-ui/primitive": "1.1.3", + "@radix-ui/react-compose-refs": "1.1.2", + "@radix-ui/react-context": "1.1.2", + "@radix-ui/react-dismissable-layer": "1.1.11", + "@radix-ui/react-focus-guards": "1.1.3", + "@radix-ui/react-focus-scope": "1.1.7", + "@radix-ui/react-id": "1.1.1", + "@radix-ui/react-portal": "1.1.9", + "@radix-ui/react-presence": "1.1.5", + "@radix-ui/react-primitive": "2.1.3", + "@radix-ui/react-slot": "1.2.3", + "@radix-ui/react-use-controllable-state": "1.2.2", + "aria-hidden": "^1.2.4", + "react-remove-scroll": "^2.6.3" + }, + "peerDependencies": { + "@types/react": "*", + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-dialog/node_modules/@radix-ui/react-slot": { + "version": "1.2.3", + "license": "MIT", + "dependencies": { + "@radix-ui/react-compose-refs": "1.1.2" + }, + "peerDependencies": { + "@types/react": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-direction": { + "version": "1.1.1", + "license": "MIT", + "peerDependencies": { + "@types/react": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-dismissable-layer": { + "version": "1.1.11", + "license": "MIT", + "dependencies": { + "@radix-ui/primitive": "1.1.3", + "@radix-ui/react-compose-refs": "1.1.2", + "@radix-ui/react-primitive": "2.1.3", + "@radix-ui/react-use-callback-ref": "1.1.1", + "@radix-ui/react-use-escape-keydown": "1.1.1" + }, + "peerDependencies": { + "@types/react": "*", + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-dropdown-menu": { + "version": "2.1.16", + "license": "MIT", + "dependencies": { + "@radix-ui/primitive": "1.1.3", + "@radix-ui/react-compose-refs": "1.1.2", + "@radix-ui/react-context": "1.1.2", + "@radix-ui/react-id": "1.1.1", + "@radix-ui/react-menu": "2.1.16", + "@radix-ui/react-primitive": "2.1.3", + "@radix-ui/react-use-controllable-state": "1.2.2" + }, + "peerDependencies": { + "@types/react": "*", + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-focus-guards": { + "version": "1.1.3", + "license": "MIT", + "peerDependencies": { + "@types/react": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-focus-scope": { + "version": "1.1.7", + "license": "MIT", + "dependencies": { + "@radix-ui/react-compose-refs": "1.1.2", + "@radix-ui/react-primitive": "2.1.3", + "@radix-ui/react-use-callback-ref": "1.1.1" + }, + "peerDependencies": { + "@types/react": "*", + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-form": { + "version": "0.1.8", + "resolved": "https://registry.npmjs.org/@radix-ui/react-form/-/react-form-0.1.8.tgz", + "integrity": "sha512-QM70k4Zwjttifr5a4sZFts9fn8FzHYvQ5PiB19O2HsYibaHSVt9fH9rzB0XZo/YcM+b7t/p7lYCT/F5eOeF5yQ==", + "license": "MIT", + "dependencies": { + "@radix-ui/primitive": "1.1.3", + "@radix-ui/react-compose-refs": "1.1.2", + "@radix-ui/react-context": "1.1.2", + "@radix-ui/react-id": "1.1.1", + "@radix-ui/react-label": "2.1.7", + "@radix-ui/react-primitive": "2.1.3" + }, + "peerDependencies": { + "@types/react": "*", + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-form/node_modules/@radix-ui/react-label": { + "version": "2.1.7", + "resolved": "https://registry.npmjs.org/@radix-ui/react-label/-/react-label-2.1.7.tgz", + "integrity": "sha512-YT1GqPSL8kJn20djelMX7/cTRp/Y9w5IZHvfxQTVHrOqa2yMl7i/UfMqKRU5V7mEyKTrUVgJXhNQPVCG8PBLoQ==", + "license": "MIT", + "dependencies": { + "@radix-ui/react-primitive": "2.1.3" + }, + "peerDependencies": { + "@types/react": "*", + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-hover-card": { + "version": "1.1.15", + "resolved": "https://registry.npmjs.org/@radix-ui/react-hover-card/-/react-hover-card-1.1.15.tgz", + "integrity": "sha512-qgTkjNT1CfKMoP0rcasmlH2r1DAiYicWsDsufxl940sT2wHNEWWv6FMWIQXWhVdmC1d/HYfbhQx60KYyAtKxjg==", + "license": "MIT", + "dependencies": { + "@radix-ui/primitive": "1.1.3", + "@radix-ui/react-compose-refs": "1.1.2", + "@radix-ui/react-context": "1.1.2", + "@radix-ui/react-dismissable-layer": "1.1.11", + "@radix-ui/react-popper": "1.2.8", + "@radix-ui/react-portal": "1.1.9", + "@radix-ui/react-presence": "1.1.5", + "@radix-ui/react-primitive": "2.1.3", + "@radix-ui/react-use-controllable-state": "1.2.2" + }, + "peerDependencies": { + "@types/react": "*", + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-id": { + "version": "1.1.1", + "license": "MIT", + "dependencies": { + "@radix-ui/react-use-layout-effect": "1.1.1" + }, + "peerDependencies": { + "@types/react": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-menu": { + "version": "2.1.16", + "license": "MIT", + "dependencies": { + "@radix-ui/primitive": "1.1.3", + "@radix-ui/react-collection": "1.1.7", + "@radix-ui/react-compose-refs": "1.1.2", + "@radix-ui/react-context": "1.1.2", + "@radix-ui/react-direction": "1.1.1", + "@radix-ui/react-dismissable-layer": "1.1.11", + "@radix-ui/react-focus-guards": "1.1.3", + "@radix-ui/react-focus-scope": "1.1.7", + "@radix-ui/react-id": "1.1.1", + "@radix-ui/react-popper": "1.2.8", + "@radix-ui/react-portal": "1.1.9", + "@radix-ui/react-presence": "1.1.5", + "@radix-ui/react-primitive": "2.1.3", + "@radix-ui/react-roving-focus": "1.1.11", + "@radix-ui/react-slot": "1.2.3", + "@radix-ui/react-use-callback-ref": "1.1.1", + "aria-hidden": "^1.2.4", + "react-remove-scroll": "^2.6.3" + }, + "peerDependencies": { + "@types/react": "*", + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-menu/node_modules/@radix-ui/react-slot": { + "version": "1.2.3", + "license": "MIT", + "dependencies": { + "@radix-ui/react-compose-refs": "1.1.2" + }, + "peerDependencies": { + "@types/react": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-menubar": { + "version": "1.1.16", + "resolved": "https://registry.npmjs.org/@radix-ui/react-menubar/-/react-menubar-1.1.16.tgz", + "integrity": "sha512-EB1FktTz5xRRi2Er974AUQZWg2yVBb1yjip38/lgwtCVRd3a+maUoGHN/xs9Yv8SY8QwbSEb+YrxGadVWbEutA==", + "license": "MIT", + "dependencies": { + "@radix-ui/primitive": "1.1.3", + "@radix-ui/react-collection": "1.1.7", + "@radix-ui/react-compose-refs": "1.1.2", + "@radix-ui/react-context": "1.1.2", + "@radix-ui/react-direction": "1.1.1", + "@radix-ui/react-id": "1.1.1", + "@radix-ui/react-menu": "2.1.16", + "@radix-ui/react-primitive": "2.1.3", + "@radix-ui/react-roving-focus": "1.1.11", + "@radix-ui/react-use-controllable-state": "1.2.2" + }, + "peerDependencies": { + "@types/react": "*", + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-navigation-menu": { + "version": "1.2.14", + "resolved": "https://registry.npmjs.org/@radix-ui/react-navigation-menu/-/react-navigation-menu-1.2.14.tgz", + "integrity": "sha512-YB9mTFQvCOAQMHU+C/jVl96WmuWeltyUEpRJJky51huhds5W2FQr1J8D/16sQlf0ozxkPK8uF3niQMdUwZPv5w==", "license": "MIT", "dependencies": { - "@radix-ui/react-slot": "1.2.4" + "@radix-ui/primitive": "1.1.3", + "@radix-ui/react-collection": "1.1.7", + "@radix-ui/react-compose-refs": "1.1.2", + "@radix-ui/react-context": "1.1.2", + "@radix-ui/react-direction": "1.1.1", + "@radix-ui/react-dismissable-layer": "1.1.11", + "@radix-ui/react-id": "1.1.1", + "@radix-ui/react-presence": "1.1.5", + "@radix-ui/react-primitive": "2.1.3", + "@radix-ui/react-use-callback-ref": "1.1.1", + "@radix-ui/react-use-controllable-state": "1.2.2", + "@radix-ui/react-use-layout-effect": "1.1.1", + "@radix-ui/react-use-previous": "1.1.1", + "@radix-ui/react-visually-hidden": "1.2.3" }, "peerDependencies": { "@types/react": "*", @@ -1262,15 +1571,79 @@ } } }, - "node_modules/@radix-ui/react-menu": { - "version": "2.1.16", + "node_modules/@radix-ui/react-one-time-password-field": { + "version": "0.1.8", + "resolved": "https://registry.npmjs.org/@radix-ui/react-one-time-password-field/-/react-one-time-password-field-0.1.8.tgz", + "integrity": "sha512-ycS4rbwURavDPVjCb5iS3aG4lURFDILi6sKI/WITUMZ13gMmn/xGjpLoqBAalhJaDk8I3UbCM5GzKHrnzwHbvg==", "license": "MIT", "dependencies": { + "@radix-ui/number": "1.1.1", "@radix-ui/primitive": "1.1.3", "@radix-ui/react-collection": "1.1.7", "@radix-ui/react-compose-refs": "1.1.2", "@radix-ui/react-context": "1.1.2", "@radix-ui/react-direction": "1.1.1", + "@radix-ui/react-primitive": "2.1.3", + "@radix-ui/react-roving-focus": "1.1.11", + "@radix-ui/react-use-controllable-state": "1.2.2", + "@radix-ui/react-use-effect-event": "0.0.2", + "@radix-ui/react-use-is-hydrated": "0.1.0", + "@radix-ui/react-use-layout-effect": "1.1.1" + }, + "peerDependencies": { + "@types/react": "*", + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-password-toggle-field": { + "version": "0.1.3", + "resolved": "https://registry.npmjs.org/@radix-ui/react-password-toggle-field/-/react-password-toggle-field-0.1.3.tgz", + "integrity": "sha512-/UuCrDBWravcaMix4TdT+qlNdVwOM1Nck9kWx/vafXsdfj1ChfhOdfi3cy9SGBpWgTXwYCuboT/oYpJy3clqfw==", + "license": "MIT", + "dependencies": { + "@radix-ui/primitive": "1.1.3", + "@radix-ui/react-compose-refs": "1.1.2", + "@radix-ui/react-context": "1.1.2", + "@radix-ui/react-id": "1.1.1", + "@radix-ui/react-primitive": "2.1.3", + "@radix-ui/react-use-controllable-state": "1.2.2", + "@radix-ui/react-use-effect-event": "0.0.2", + "@radix-ui/react-use-is-hydrated": "0.1.0" + }, + "peerDependencies": { + "@types/react": "*", + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-popover": { + "version": "1.1.15", + "resolved": "https://registry.npmjs.org/@radix-ui/react-popover/-/react-popover-1.1.15.tgz", + "integrity": "sha512-kr0X2+6Yy/vJzLYJUPCZEc8SfQcf+1COFoAqauJm74umQhta9M7lNJHP7QQS3vkvcGLQUbWpMzwrXYwrYztHKA==", + "license": "MIT", + "dependencies": { + "@radix-ui/primitive": "1.1.3", + "@radix-ui/react-compose-refs": "1.1.2", + "@radix-ui/react-context": "1.1.2", "@radix-ui/react-dismissable-layer": "1.1.11", "@radix-ui/react-focus-guards": "1.1.3", "@radix-ui/react-focus-scope": "1.1.7", @@ -1279,9 +1652,8 @@ "@radix-ui/react-portal": "1.1.9", "@radix-ui/react-presence": "1.1.5", "@radix-ui/react-primitive": "2.1.3", - "@radix-ui/react-roving-focus": "1.1.11", "@radix-ui/react-slot": "1.2.3", - "@radix-ui/react-use-callback-ref": "1.1.1", + "@radix-ui/react-use-controllable-state": "1.2.2", "aria-hidden": "^1.2.4", "react-remove-scroll": "^2.6.3" }, @@ -1300,8 +1672,10 @@ } } }, - "node_modules/@radix-ui/react-menu/node_modules/@radix-ui/react-slot": { + "node_modules/@radix-ui/react-popover/node_modules/@radix-ui/react-slot": { "version": "1.2.3", + "resolved": "https://registry.npmjs.org/@radix-ui/react-slot/-/react-slot-1.2.3.tgz", + "integrity": "sha512-aeNmHnBxbi2St0au6VBVC7JXFlhLlOnvIIlePNniyUNAClzmtAUEY8/pBiK3iHjufOlwA+c20/8jngo7xcrg8A==", "license": "MIT", "dependencies": { "@radix-ui/react-compose-refs": "1.1.2" @@ -1427,6 +1801,62 @@ } } }, + "node_modules/@radix-ui/react-progress": { + "version": "1.1.7", + "resolved": "https://registry.npmjs.org/@radix-ui/react-progress/-/react-progress-1.1.7.tgz", + "integrity": "sha512-vPdg/tF6YC/ynuBIJlk1mm7Le0VgW6ub6J2UWnTQ7/D23KXcPI1qy+0vBkgKgd38RCMJavBXpB83HPNFMTb0Fg==", + "license": "MIT", + "dependencies": { + "@radix-ui/react-context": "1.1.2", + "@radix-ui/react-primitive": "2.1.3" + }, + "peerDependencies": { + "@types/react": "*", + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-radio-group": { + "version": "1.3.8", + "resolved": "https://registry.npmjs.org/@radix-ui/react-radio-group/-/react-radio-group-1.3.8.tgz", + "integrity": "sha512-VBKYIYImA5zsxACdisNQ3BjCBfmbGH3kQlnFVqlWU4tXwjy7cGX8ta80BcrO+WJXIn5iBylEH3K6ZTlee//lgQ==", + "license": "MIT", + "dependencies": { + "@radix-ui/primitive": "1.1.3", + "@radix-ui/react-compose-refs": "1.1.2", + "@radix-ui/react-context": "1.1.2", + "@radix-ui/react-direction": "1.1.1", + "@radix-ui/react-presence": "1.1.5", + "@radix-ui/react-primitive": "2.1.3", + "@radix-ui/react-roving-focus": "1.1.11", + "@radix-ui/react-use-controllable-state": "1.2.2", + "@radix-ui/react-use-previous": "1.1.1", + "@radix-ui/react-use-size": "1.1.1" + }, + "peerDependencies": { + "@types/react": "*", + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } + } + }, "node_modules/@radix-ui/react-roving-focus": { "version": "1.1.11", "license": "MIT", @@ -1542,11 +1972,23 @@ } } }, - "node_modules/@radix-ui/react-separator": { - "version": "1.1.8", + "node_modules/@radix-ui/react-slider": { + "version": "1.3.6", + "resolved": "https://registry.npmjs.org/@radix-ui/react-slider/-/react-slider-1.3.6.tgz", + "integrity": "sha512-JPYb1GuM1bxfjMRlNLE+BcmBC8onfCi60Blk7OBqi2MLTFdS+8401U4uFjnwkOr49BLmXxLC6JHkvAsx5OJvHw==", "license": "MIT", "dependencies": { - "@radix-ui/react-primitive": "2.1.4" + "@radix-ui/number": "1.1.1", + "@radix-ui/primitive": "1.1.3", + "@radix-ui/react-collection": "1.1.7", + "@radix-ui/react-compose-refs": "1.1.2", + "@radix-ui/react-context": "1.1.2", + "@radix-ui/react-direction": "1.1.1", + "@radix-ui/react-primitive": "2.1.3", + "@radix-ui/react-use-controllable-state": "1.2.2", + "@radix-ui/react-use-layout-effect": "1.1.1", + "@radix-ui/react-use-previous": "1.1.1", + "@radix-ui/react-use-size": "1.1.1" }, "peerDependencies": { "@types/react": "*", @@ -1563,11 +2005,17 @@ } } }, - "node_modules/@radix-ui/react-separator/node_modules/@radix-ui/react-primitive": { - "version": "2.1.4", + "node_modules/@radix-ui/react-switch": { + "version": "1.2.6", "license": "MIT", "dependencies": { - "@radix-ui/react-slot": "1.2.4" + "@radix-ui/primitive": "1.1.3", + "@radix-ui/react-compose-refs": "1.1.2", + "@radix-ui/react-context": "1.1.2", + "@radix-ui/react-primitive": "2.1.3", + "@radix-ui/react-use-controllable-state": "1.2.2", + "@radix-ui/react-use-previous": "1.1.1", + "@radix-ui/react-use-size": "1.1.1" }, "peerDependencies": { "@types/react": "*", @@ -1584,33 +2032,50 @@ } } }, - "node_modules/@radix-ui/react-slot": { - "version": "1.2.4", + "node_modules/@radix-ui/react-tabs": { + "version": "1.1.13", "license": "MIT", "dependencies": { - "@radix-ui/react-compose-refs": "1.1.2" + "@radix-ui/primitive": "1.1.3", + "@radix-ui/react-context": "1.1.2", + "@radix-ui/react-direction": "1.1.1", + "@radix-ui/react-id": "1.1.1", + "@radix-ui/react-presence": "1.1.5", + "@radix-ui/react-primitive": "2.1.3", + "@radix-ui/react-roving-focus": "1.1.11", + "@radix-ui/react-use-controllable-state": "1.2.2" }, "peerDependencies": { "@types/react": "*", - "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "peerDependenciesMeta": { "@types/react": { "optional": true + }, + "@types/react-dom": { + "optional": true } } }, - "node_modules/@radix-ui/react-switch": { - "version": "1.2.6", + "node_modules/@radix-ui/react-toast": { + "version": "1.2.15", "license": "MIT", "dependencies": { "@radix-ui/primitive": "1.1.3", + "@radix-ui/react-collection": "1.1.7", "@radix-ui/react-compose-refs": "1.1.2", "@radix-ui/react-context": "1.1.2", + "@radix-ui/react-dismissable-layer": "1.1.11", + "@radix-ui/react-portal": "1.1.9", + "@radix-ui/react-presence": "1.1.5", "@radix-ui/react-primitive": "2.1.3", + "@radix-ui/react-use-callback-ref": "1.1.1", "@radix-ui/react-use-controllable-state": "1.2.2", - "@radix-ui/react-use-previous": "1.1.1", - "@radix-ui/react-use-size": "1.1.1" + "@radix-ui/react-use-layout-effect": "1.1.1", + "@radix-ui/react-visually-hidden": "1.2.3" }, "peerDependencies": { "@types/react": "*", @@ -1627,17 +2092,43 @@ } } }, - "node_modules/@radix-ui/react-tabs": { - "version": "1.1.13", + "node_modules/@radix-ui/react-toggle": { + "version": "1.1.10", + "resolved": "https://registry.npmjs.org/@radix-ui/react-toggle/-/react-toggle-1.1.10.tgz", + "integrity": "sha512-lS1odchhFTeZv3xwHH31YPObmJn8gOg7Lq12inrr0+BH/l3Tsq32VfjqH1oh80ARM3mlkfMic15n0kg4sD1poQ==", + "license": "MIT", + "dependencies": { + "@radix-ui/primitive": "1.1.3", + "@radix-ui/react-primitive": "2.1.3", + "@radix-ui/react-use-controllable-state": "1.2.2" + }, + "peerDependencies": { + "@types/react": "*", + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-toggle-group": { + "version": "1.1.11", + "resolved": "https://registry.npmjs.org/@radix-ui/react-toggle-group/-/react-toggle-group-1.1.11.tgz", + "integrity": "sha512-5umnS0T8JQzQT6HbPyO7Hh9dgd82NmS36DQr+X/YJ9ctFNCiiQd6IJAYYZ33LUwm8M+taCz5t2ui29fHZc4Y6Q==", "license": "MIT", "dependencies": { "@radix-ui/primitive": "1.1.3", "@radix-ui/react-context": "1.1.2", "@radix-ui/react-direction": "1.1.1", - "@radix-ui/react-id": "1.1.1", - "@radix-ui/react-presence": "1.1.5", "@radix-ui/react-primitive": "2.1.3", "@radix-ui/react-roving-focus": "1.1.11", + "@radix-ui/react-toggle": "1.1.10", "@radix-ui/react-use-controllable-state": "1.2.2" }, "peerDependencies": { @@ -1655,22 +2146,42 @@ } } }, - "node_modules/@radix-ui/react-toast": { - "version": "1.2.15", + "node_modules/@radix-ui/react-toolbar": { + "version": "1.1.11", + "resolved": "https://registry.npmjs.org/@radix-ui/react-toolbar/-/react-toolbar-1.1.11.tgz", + "integrity": "sha512-4ol06/1bLoFu1nwUqzdD4Y5RZ9oDdKeiHIsntug54Hcr1pgaHiPqHFEaXI1IFP/EsOfROQZ8Mig9VTIRza6Tjg==", "license": "MIT", "dependencies": { "@radix-ui/primitive": "1.1.3", - "@radix-ui/react-collection": "1.1.7", - "@radix-ui/react-compose-refs": "1.1.2", "@radix-ui/react-context": "1.1.2", - "@radix-ui/react-dismissable-layer": "1.1.11", - "@radix-ui/react-portal": "1.1.9", - "@radix-ui/react-presence": "1.1.5", + "@radix-ui/react-direction": "1.1.1", "@radix-ui/react-primitive": "2.1.3", - "@radix-ui/react-use-callback-ref": "1.1.1", - "@radix-ui/react-use-controllable-state": "1.2.2", - "@radix-ui/react-use-layout-effect": "1.1.1", - "@radix-ui/react-visually-hidden": "1.2.3" + "@radix-ui/react-roving-focus": "1.1.11", + "@radix-ui/react-separator": "1.1.7", + "@radix-ui/react-toggle-group": "1.1.11" + }, + "peerDependencies": { + "@types/react": "*", + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-toolbar/node_modules/@radix-ui/react-separator": { + "version": "1.1.7", + "resolved": "https://registry.npmjs.org/@radix-ui/react-separator/-/react-separator-1.1.7.tgz", + "integrity": "sha512-0HEb8R9E8A+jZjvmFCy/J4xhbXy3TV+9XSnGJ3KvTtjlIUy/YQ/p6UYZvi7YbeoeXdyU9+Y3scizK6hkY37baA==", + "license": "MIT", + "dependencies": { + "@radix-ui/react-primitive": "2.1.3" }, "peerDependencies": { "@types/react": "*", @@ -1797,6 +2308,24 @@ } } }, + "node_modules/@radix-ui/react-use-is-hydrated": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/@radix-ui/react-use-is-hydrated/-/react-use-is-hydrated-0.1.0.tgz", + "integrity": "sha512-U+UORVEq+cTnRIaostJv9AGdV3G6Y+zbVd+12e18jQ5A3c0xL03IhnHuiU4UV69wolOQp5GfR58NW/EgdQhwOA==", + "license": "MIT", + "dependencies": { + "use-sync-external-store": "^1.5.0" + }, + "peerDependencies": { + "@types/react": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, "node_modules/@radix-ui/react-use-layout-effect": { "version": "1.1.1", "license": "MIT", @@ -1905,9 +2434,9 @@ } }, "node_modules/@rolldown/binding-android-arm64": { - "version": "1.0.0-rc.15", - "resolved": "https://registry.npmjs.org/@rolldown/binding-android-arm64/-/binding-android-arm64-1.0.0-rc.15.tgz", - "integrity": "sha512-YYe6aWruPZDtHNpwu7+qAHEMbQ/yRl6atqb/AhznLTnD3UY99Q1jE7ihLSahNWkF4EqRPVC4SiR4O0UkLK02tA==", + "version": "1.0.0-rc.17", + "resolved": "https://registry.npmjs.org/@rolldown/binding-android-arm64/-/binding-android-arm64-1.0.0-rc.17.tgz", + "integrity": "sha512-s70pVGhw4zqGeFnXWvAzJDlvxhlRollagdCCKRgOsgUOH3N1l0LIxf83AtGzmb5SiVM4Hjl5HyarMRfdfj3DaQ==", "cpu": [ "arm64" ], @@ -1922,9 +2451,9 @@ } }, "node_modules/@rolldown/binding-darwin-arm64": { - "version": "1.0.0-rc.15", - "resolved": "https://registry.npmjs.org/@rolldown/binding-darwin-arm64/-/binding-darwin-arm64-1.0.0-rc.15.tgz", - "integrity": "sha512-oArR/ig8wNTPYsXL+Mzhs0oxhxfuHRfG7Ikw7jXsw8mYOtk71W0OkF2VEVh699pdmzjPQsTjlD1JIOoHkLP1Fg==", + "version": "1.0.0-rc.17", + "resolved": "https://registry.npmjs.org/@rolldown/binding-darwin-arm64/-/binding-darwin-arm64-1.0.0-rc.17.tgz", + "integrity": "sha512-4ksWc9n0mhlZpZ9PMZgTGjeOPRu8MB1Z3Tz0Mo02eWfWCHMW1zN82Qz/pL/rC+yQa+8ZnutMF0JjJe7PjwasYw==", "cpu": [ "arm64" ], @@ -1939,9 +2468,9 @@ } }, "node_modules/@rolldown/binding-darwin-x64": { - "version": "1.0.0-rc.15", - "resolved": "https://registry.npmjs.org/@rolldown/binding-darwin-x64/-/binding-darwin-x64-1.0.0-rc.15.tgz", - "integrity": "sha512-YzeVqOqjPYvUbJSWJ4EDL8ahbmsIXQpgL3JVipmN+MX0XnXMeWomLN3Fb+nwCmP/jfyqte5I3XRSm7OfQrbyxw==", + "version": "1.0.0-rc.17", + "resolved": "https://registry.npmjs.org/@rolldown/binding-darwin-x64/-/binding-darwin-x64-1.0.0-rc.17.tgz", + "integrity": "sha512-SUSDOI6WwUVNcWxd02QEBjLdY1VPHvlEkw6T/8nYG322iYWCTxRb1vzk4E+mWWYehTp7ERibq54LSJGjmouOsw==", "cpu": [ "x64" ], @@ -1956,9 +2485,9 @@ } }, "node_modules/@rolldown/binding-freebsd-x64": { - "version": "1.0.0-rc.15", - "resolved": "https://registry.npmjs.org/@rolldown/binding-freebsd-x64/-/binding-freebsd-x64-1.0.0-rc.15.tgz", - "integrity": "sha512-9Erhx956jeQ0nNTyif1+QWAXDRD38ZNjr//bSHrt6wDwB+QkAfl2q6Mn1k6OBPerznjRmbM10lgRb1Pli4xZPw==", + "version": "1.0.0-rc.17", + "resolved": "https://registry.npmjs.org/@rolldown/binding-freebsd-x64/-/binding-freebsd-x64-1.0.0-rc.17.tgz", + "integrity": "sha512-hwnz3nw9dbJ05EDO/PvcjaaewqqDy7Y1rn1UO81l8iIK1GjenME75dl16ajbvSSMfv66WXSRCYKIqfgq2KCfxw==", "cpu": [ "x64" ], @@ -1973,9 +2502,9 @@ } }, "node_modules/@rolldown/binding-linux-arm-gnueabihf": { - "version": "1.0.0-rc.15", - "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-arm-gnueabihf/-/binding-linux-arm-gnueabihf-1.0.0-rc.15.tgz", - "integrity": "sha512-cVwk0w8QbZJGTnP/AHQBs5yNwmpgGYStL88t4UIaqcvYJWBfS0s3oqVLZPwsPU6M0zlW4GqjP0Zq5MnAGwFeGA==", + "version": "1.0.0-rc.17", + "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-arm-gnueabihf/-/binding-linux-arm-gnueabihf-1.0.0-rc.17.tgz", + "integrity": "sha512-IS+W7epTcwANmFSQFrS1SivEXHtl1JtuQA9wlxrZTcNi6mx+FDOYrakGevvvTwgj2JvWiK8B29/qD9BELZPyXQ==", "cpu": [ "arm" ], @@ -1990,13 +2519,16 @@ } }, "node_modules/@rolldown/binding-linux-arm64-gnu": { - "version": "1.0.0-rc.15", - "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-arm64-gnu/-/binding-linux-arm64-gnu-1.0.0-rc.15.tgz", - "integrity": "sha512-eBZ/u8iAK9SoHGanqe/jrPnY0JvBN6iXbVOsbO38mbz+ZJsaobExAm1Iu+rxa4S1l2FjG0qEZn4Rc6X8n+9M+w==", + "version": "1.0.0-rc.17", + "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-arm64-gnu/-/binding-linux-arm64-gnu-1.0.0-rc.17.tgz", + "integrity": "sha512-e6usGaHKW5BMNZOymS1UcEYGowQMWcgZ71Z17Sl/h2+ZziNJ1a9n3Zvcz6LdRyIW5572wBCTH/Z+bKuZouGk9Q==", "cpu": [ "arm64" ], "dev": true, + "libc": [ + "glibc" + ], "license": "MIT", "optional": true, "os": [ @@ -2007,13 +2539,16 @@ } }, "node_modules/@rolldown/binding-linux-arm64-musl": { - "version": "1.0.0-rc.15", - "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-arm64-musl/-/binding-linux-arm64-musl-1.0.0-rc.15.tgz", - "integrity": "sha512-ZvRYMGrAklV9PEkgt4LQM6MjQX2P58HPAuecwYObY2DhS2t35R0I810bKi0wmaYORt6m/2Sm+Z+nFgb0WhXNcQ==", + "version": "1.0.0-rc.17", + "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-arm64-musl/-/binding-linux-arm64-musl-1.0.0-rc.17.tgz", + "integrity": "sha512-b/CgbwAJpmrRLp02RPfhbudf5tZnN9nsPWK82znefso832etkem8H7FSZwxrOI9djcdTP7U6YfNhbRnh7djErg==", "cpu": [ "arm64" ], "dev": true, + "libc": [ + "musl" + ], "license": "MIT", "optional": true, "os": [ @@ -2024,13 +2559,16 @@ } }, "node_modules/@rolldown/binding-linux-ppc64-gnu": { - "version": "1.0.0-rc.15", - "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-ppc64-gnu/-/binding-linux-ppc64-gnu-1.0.0-rc.15.tgz", - "integrity": "sha512-VDpgGBzgfg5hLg+uBpCLoFG5kVvEyafmfxGUV0UHLcL5irxAK7PKNeC2MwClgk6ZAiNhmo9FLhRYgvMmedLtnQ==", + "version": "1.0.0-rc.17", + "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-ppc64-gnu/-/binding-linux-ppc64-gnu-1.0.0-rc.17.tgz", + "integrity": "sha512-4EII1iNGRUN5WwGbF/kOh/EIkoDN9HsupgLQoXfY+D1oyJm7/F4t5PYU5n8SWZgG0FEwakyM8pGgwcBYruGTlA==", "cpu": [ "ppc64" ], "dev": true, + "libc": [ + "glibc" + ], "license": "MIT", "optional": true, "os": [ @@ -2041,13 +2579,16 @@ } }, "node_modules/@rolldown/binding-linux-s390x-gnu": { - "version": "1.0.0-rc.15", - "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-s390x-gnu/-/binding-linux-s390x-gnu-1.0.0-rc.15.tgz", - "integrity": "sha512-y1uXY3qQWCzcPgRJATPSOUP4tCemh4uBdY7e3EZbVwCJTY3gLJWnQABgeUetvED+bt1FQ01OeZwvhLS2bpNrAQ==", + "version": "1.0.0-rc.17", + "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-s390x-gnu/-/binding-linux-s390x-gnu-1.0.0-rc.17.tgz", + "integrity": "sha512-AH8oq3XqQo4IibpVXvPeLDI5pzkpYn0WiZAfT05kFzoJ6tQNzwRdDYQ45M8I/gslbodRZwW8uxLhbSBbkv96rA==", "cpu": [ "s390x" ], "dev": true, + "libc": [ + "glibc" + ], "license": "MIT", "optional": true, "os": [ @@ -2058,13 +2599,16 @@ } }, "node_modules/@rolldown/binding-linux-x64-gnu": { - "version": "1.0.0-rc.15", - "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-x64-gnu/-/binding-linux-x64-gnu-1.0.0-rc.15.tgz", - "integrity": "sha512-023bTPBod7J3Y/4fzAN6QtpkSABR0rigtrwaP+qSEabUh5zf6ELr9Nc7GujaROuPY3uwdSIXWrvhn1KxOvurWA==", + "version": "1.0.0-rc.17", + "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-x64-gnu/-/binding-linux-x64-gnu-1.0.0-rc.17.tgz", + "integrity": "sha512-cLnjV3xfo7KslbU41Z7z8BH/E1y5mzUYzAqih1d1MDaIGZRCMqTijqLv76/P7fyHuvUcfGsIpqCdddbxLLK9rA==", "cpu": [ "x64" ], "dev": true, + "libc": [ + "glibc" + ], "license": "MIT", "optional": true, "os": [ @@ -2075,13 +2619,16 @@ } }, "node_modules/@rolldown/binding-linux-x64-musl": { - "version": "1.0.0-rc.15", - "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-x64-musl/-/binding-linux-x64-musl-1.0.0-rc.15.tgz", - "integrity": "sha512-witB2O0/hU4CgfOOKUoeFgQ4GktPi1eEbAhaLAIpgD6+ZnhcPkUtPsoKKHRzmOoWPZue46IThdSgdo4XneOLYw==", + "version": "1.0.0-rc.17", + "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-x64-musl/-/binding-linux-x64-musl-1.0.0-rc.17.tgz", + "integrity": "sha512-0phclDw1spsL7dUB37sIARuis2tAgomCJXAHZlpt8PXZ4Ba0dRP1e+66lsRqrfhISeN9bEGNjQs+T/Fbd7oYGw==", "cpu": [ "x64" ], "dev": true, + "libc": [ + "musl" + ], "license": "MIT", "optional": true, "os": [ @@ -2092,9 +2639,9 @@ } }, "node_modules/@rolldown/binding-openharmony-arm64": { - "version": "1.0.0-rc.15", - "resolved": "https://registry.npmjs.org/@rolldown/binding-openharmony-arm64/-/binding-openharmony-arm64-1.0.0-rc.15.tgz", - "integrity": "sha512-UCL68NJ0Ud5zRipXZE9dF5PmirzJE4E4BCIOOssEnM7wLDsxjc6Qb0sGDxTNRTP53I6MZpygyCpY8Aa8sPfKPg==", + "version": "1.0.0-rc.17", + "resolved": "https://registry.npmjs.org/@rolldown/binding-openharmony-arm64/-/binding-openharmony-arm64-1.0.0-rc.17.tgz", + "integrity": "sha512-0ag/hEgXOwgw4t8QyQvUCxvEg+V0KBcA6YuOx9g0r02MprutRF5dyljgm3EmR02O292UX7UeS6HzWHAl6KgyhA==", "cpu": [ "arm64" ], @@ -2109,9 +2656,9 @@ } }, "node_modules/@rolldown/binding-wasm32-wasi": { - "version": "1.0.0-rc.15", - "resolved": "https://registry.npmjs.org/@rolldown/binding-wasm32-wasi/-/binding-wasm32-wasi-1.0.0-rc.15.tgz", - "integrity": "sha512-ApLruZq/ig+nhaE7OJm4lDjayUnOHVUa77zGeqnqZ9pn0ovdVbbNPerVibLXDmWeUZXjIYIT8V3xkT58Rm9u5Q==", + "version": "1.0.0-rc.17", + "resolved": "https://registry.npmjs.org/@rolldown/binding-wasm32-wasi/-/binding-wasm32-wasi-1.0.0-rc.17.tgz", + "integrity": "sha512-LEXei6vo0E5wTGwpkJ4KoT3OZJRnglwldt5ziLzOlc6qqb55z4tWNq2A+PFqCJuvWWdP53CVhG1Z9NtToDPJrA==", "cpu": [ "wasm32" ], @@ -2119,18 +2666,18 @@ "license": "MIT", "optional": true, "dependencies": { - "@emnapi/core": "1.9.2", - "@emnapi/runtime": "1.9.2", - "@napi-rs/wasm-runtime": "^1.1.3" + "@emnapi/core": "1.10.0", + "@emnapi/runtime": "1.10.0", + "@napi-rs/wasm-runtime": "^1.1.4" }, "engines": { - "node": ">=14.0.0" + "node": "^20.19.0 || >=22.12.0" } }, "node_modules/@rolldown/binding-win32-arm64-msvc": { - "version": "1.0.0-rc.15", - "resolved": "https://registry.npmjs.org/@rolldown/binding-win32-arm64-msvc/-/binding-win32-arm64-msvc-1.0.0-rc.15.tgz", - "integrity": "sha512-KmoUoU7HnN+Si5YWJigfTws1jz1bKBYDQKdbLspz0UaqjjFkddHsqorgiW1mxcAj88lYUE6NC/zJNwT+SloqtA==", + "version": "1.0.0-rc.17", + "resolved": "https://registry.npmjs.org/@rolldown/binding-win32-arm64-msvc/-/binding-win32-arm64-msvc-1.0.0-rc.17.tgz", + "integrity": "sha512-gUmyzBl3SPMa6hrqFUth9sVfcLBlYsbMzBx5PlexMroZStgzGqlZ26pYG89rBb45Mnia+oil6YAIFeEWGWhoZA==", "cpu": [ "arm64" ], @@ -2145,9 +2692,9 @@ } }, "node_modules/@rolldown/binding-win32-x64-msvc": { - "version": "1.0.0-rc.15", - "resolved": "https://registry.npmjs.org/@rolldown/binding-win32-x64-msvc/-/binding-win32-x64-msvc-1.0.0-rc.15.tgz", - "integrity": "sha512-3P2A8L+x75qavWLe/Dll3EYBJLQmtkJN8rfh+U/eR3MqMgL/h98PhYI+JFfXuDPgPeCB7iZAKiqii5vqOvnA0g==", + "version": "1.0.0-rc.17", + "resolved": "https://registry.npmjs.org/@rolldown/binding-win32-x64-msvc/-/binding-win32-x64-msvc-1.0.0-rc.17.tgz", + "integrity": "sha512-3hkiolcUAvPB9FLb3UZdfjVVNWherN1f/skkGWJP/fgSQhYUZpSIRr0/I8ZK9TkF3F7kxvJAk0+IcKvPHk9qQg==", "cpu": [ "x64" ], @@ -2606,6 +3153,13 @@ "dev": true, "license": "MIT" }, + "node_modules/@types/esrecurse": { + "version": "4.3.1", + "resolved": "https://registry.npmjs.org/@types/esrecurse/-/esrecurse-4.3.1.tgz", + "integrity": "sha512-xJBAbDifo5hpffDBuHl0Y8ywswbiAp/Wi7Y/GtAgSlZyIABppyurxVueOPE8LUQOxdlgi6Zqce7uoEpqNTeiUw==", + "dev": true, + "license": "MIT" + }, "node_modules/@types/estree": { "version": "1.0.8", "dev": true, @@ -2613,17 +3167,19 @@ }, "node_modules/@types/json-schema": { "version": "7.0.15", + "resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.15.tgz", + "integrity": "sha512-5+fP8P8MFNC+AyZCDxrB2pkZFPGzqQWUzpSeuuVLvm8VMcorNYavBqoFcxK8bQz4Qsbn4oUEEem4wDLfcysGHA==", "dev": true, "license": "MIT" }, "node_modules/@types/node": { - "version": "25.5.2", - "resolved": "https://registry.npmjs.org/@types/node/-/node-25.5.2.tgz", - "integrity": "sha512-tO4ZIRKNC+MDWV4qKVZe3Ql/woTnmHDr5JD8UI5hn2pwBrHEwOEMZK7WlNb5RKB6EoJ02gwmQS9OrjuFnZYdpg==", + "version": "25.6.0", + "resolved": "https://registry.npmjs.org/@types/node/-/node-25.6.0.tgz", + "integrity": "sha512-+qIYRKdNYJwY3vRCZMdJbPLJAtGjQBudzZzdzwQYkEPQd+PJGixUL5QfvCLDaULoLv+RhT3LDkwEfKaAkgSmNQ==", "dev": true, "license": "MIT", "dependencies": { - "undici-types": "~7.18.0" + "undici-types": "~7.19.0" } }, "node_modules/@types/react": { @@ -2653,17 +3209,17 @@ "license": "MIT" }, "node_modules/@typescript-eslint/eslint-plugin": { - "version": "8.58.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-8.58.0.tgz", - "integrity": "sha512-RLkVSiNuUP1C2ROIWfqX+YcUfLaSnxGE/8M+Y57lopVwg9VTYYfhuz15Yf1IzCKgZj6/rIbYTmJCUSqr76r0Wg==", + "version": "8.59.2", + "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-8.59.2.tgz", + "integrity": "sha512-j/bwmkBvHUtPNxzuWe5z6BEk3q54YRyGlBXkSsmfoih7zNrBvl5A9A98anlp/7JbyZcWIJ8KXo/3Tq/DjFLtuQ==", "dev": true, "license": "MIT", "dependencies": { "@eslint-community/regexpp": "^4.12.2", - "@typescript-eslint/scope-manager": "8.58.0", - "@typescript-eslint/type-utils": "8.58.0", - "@typescript-eslint/utils": "8.58.0", - "@typescript-eslint/visitor-keys": "8.58.0", + "@typescript-eslint/scope-manager": "8.59.2", + "@typescript-eslint/type-utils": "8.59.2", + "@typescript-eslint/utils": "8.59.2", + "@typescript-eslint/visitor-keys": "8.59.2", "ignore": "^7.0.5", "natural-compare": "^1.4.0", "ts-api-utils": "^2.5.0" @@ -2676,22 +3232,22 @@ "url": "https://opencollective.com/typescript-eslint" }, "peerDependencies": { - "@typescript-eslint/parser": "^8.58.0", + "@typescript-eslint/parser": "^8.59.2", "eslint": "^8.57.0 || ^9.0.0 || ^10.0.0", "typescript": ">=4.8.4 <6.1.0" } }, "node_modules/@typescript-eslint/parser": { - "version": "8.58.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-8.58.0.tgz", - "integrity": "sha512-rLoGZIf9afaRBYsPUMtvkDWykwXwUPL60HebR4JgTI8mxfFe2cQTu3AGitANp4b9B2QlVru6WzjgB2IzJKiCSA==", + "version": "8.59.2", + "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-8.59.2.tgz", + "integrity": "sha512-plR3pp6D+SSUn1HM7xvSkx12/DhoHInI2YF35KAcVFNZvlC0gtrWqx7Qq1oH2Ssgi0vlFRCTbP+DZc7B9+TtsQ==", "dev": true, "license": "MIT", "dependencies": { - "@typescript-eslint/scope-manager": "8.58.0", - "@typescript-eslint/types": "8.58.0", - "@typescript-eslint/typescript-estree": "8.58.0", - "@typescript-eslint/visitor-keys": "8.58.0", + "@typescript-eslint/scope-manager": "8.59.2", + "@typescript-eslint/types": "8.59.2", + "@typescript-eslint/typescript-estree": "8.59.2", + "@typescript-eslint/visitor-keys": "8.59.2", "debug": "^4.4.3" }, "engines": { @@ -2707,14 +3263,14 @@ } }, "node_modules/@typescript-eslint/project-service": { - "version": "8.58.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/project-service/-/project-service-8.58.0.tgz", - "integrity": "sha512-8Q/wBPWLQP1j16NxoPNIKpDZFMaxl7yWIoqXWYeWO+Bbd2mjgvoF0dxP2jKZg5+x49rgKdf7Ck473M8PC3V9lg==", + "version": "8.59.2", + "resolved": "https://registry.npmjs.org/@typescript-eslint/project-service/-/project-service-8.59.2.tgz", + "integrity": "sha512-+2hqvEkeyf/0FBor67duF0Ll7Ot8jyKzDQOSrxazF/danillRq2DwR9dLptsXpoZQqxE1UisSmoZewrlPas9Vw==", "dev": true, "license": "MIT", "dependencies": { - "@typescript-eslint/tsconfig-utils": "^8.58.0", - "@typescript-eslint/types": "^8.58.0", + "@typescript-eslint/tsconfig-utils": "^8.59.2", + "@typescript-eslint/types": "^8.59.2", "debug": "^4.4.3" }, "engines": { @@ -2729,14 +3285,14 @@ } }, "node_modules/@typescript-eslint/scope-manager": { - "version": "8.58.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-8.58.0.tgz", - "integrity": "sha512-W1Lur1oF50FxSnNdGp3Vs6P+yBRSmZiw4IIjEeYxd8UQJwhUF0gDgDD/W/Tgmh73mxgEU3qX0Bzdl/NGuSPEpQ==", + "version": "8.59.2", + "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-8.59.2.tgz", + "integrity": "sha512-JzfyEpEtOU89CcFSwyNS3mu4MLvLSXqnmX05+aKBDM+TdR5jzcGOEBwxwGNxrEQ7p/z6kK2WyioCGBf2zZBnvg==", "dev": true, "license": "MIT", "dependencies": { - "@typescript-eslint/types": "8.58.0", - "@typescript-eslint/visitor-keys": "8.58.0" + "@typescript-eslint/types": "8.59.2", + "@typescript-eslint/visitor-keys": "8.59.2" }, "engines": { "node": "^18.18.0 || ^20.9.0 || >=21.1.0" @@ -2747,9 +3303,9 @@ } }, "node_modules/@typescript-eslint/tsconfig-utils": { - "version": "8.58.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/tsconfig-utils/-/tsconfig-utils-8.58.0.tgz", - "integrity": "sha512-doNSZEVJsWEu4htiVC+PR6NpM+pa+a4ClH9INRWOWCUzMst/VA9c4gXq92F8GUD1rwhNvRLkgjfYtFXegXQF7A==", + "version": "8.59.2", + "resolved": "https://registry.npmjs.org/@typescript-eslint/tsconfig-utils/-/tsconfig-utils-8.59.2.tgz", + "integrity": "sha512-BKK4alN7oi4C/zv4VqHQ+uRU+lTa6JGIZ7s1juw7b3RHo9OfKB+bKX3u0iVZetdsUCBBkSbdWbarJbmN0fTeSw==", "dev": true, "license": "MIT", "engines": { @@ -2764,15 +3320,15 @@ } }, "node_modules/@typescript-eslint/type-utils": { - "version": "8.58.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-8.58.0.tgz", - "integrity": "sha512-aGsCQImkDIqMyx1u4PrVlbi/krmDsQUs4zAcCV6M7yPcPev+RqVlndsJy9kJ8TLihW9TZ0kbDAzctpLn5o+lOg==", + "version": "8.59.2", + "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-8.59.2.tgz", + "integrity": "sha512-nhqaj1nmTdVVl/BP5omXNRGO38jn5iosis2vbdmupF2txCf8ylWT8lx+JlvMYYVqzGVKtjojUFoQ3JRWK+mfzQ==", "dev": true, "license": "MIT", "dependencies": { - "@typescript-eslint/types": "8.58.0", - "@typescript-eslint/typescript-estree": "8.58.0", - "@typescript-eslint/utils": "8.58.0", + "@typescript-eslint/types": "8.59.2", + "@typescript-eslint/typescript-estree": "8.59.2", + "@typescript-eslint/utils": "8.59.2", "debug": "^4.4.3", "ts-api-utils": "^2.5.0" }, @@ -2789,9 +3345,9 @@ } }, "node_modules/@typescript-eslint/types": { - "version": "8.58.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-8.58.0.tgz", - "integrity": "sha512-O9CjxypDT89fbHxRfETNoAnHj/i6IpRK0CvbVN3qibxlLdo5p5hcLmUuCCrHMpxiWSwKyI8mCP7qRNYuOJ0Uww==", + "version": "8.59.2", + "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-8.59.2.tgz", + "integrity": "sha512-e82GVOE8Ps3E++Egvb6Y3Dw0S10u8NkQ9KXmtRhCWJJ8kDhOJTvtMAWnFL16kB1583goCWXsr0NieKCZMs2/0Q==", "dev": true, "license": "MIT", "engines": { @@ -2803,16 +3359,16 @@ } }, "node_modules/@typescript-eslint/typescript-estree": { - "version": "8.58.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-8.58.0.tgz", - "integrity": "sha512-7vv5UWbHqew/dvs+D3e1RvLv1v2eeZ9txRHPnEEBUgSNLx5ghdzjHa0sgLWYVKssH+lYmV0JaWdoubo0ncGYLA==", + "version": "8.59.2", + "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-8.59.2.tgz", + "integrity": "sha512-o0XPGNwcWw+FIwStOWn+BwBuEmL6QXP0rsvAFg7ET1dey1Nr6Wb1ac8p5HEsK0ygO/6mUxlk+YWQD9xcb/nnXg==", "dev": true, "license": "MIT", "dependencies": { - "@typescript-eslint/project-service": "8.58.0", - "@typescript-eslint/tsconfig-utils": "8.58.0", - "@typescript-eslint/types": "8.58.0", - "@typescript-eslint/visitor-keys": "8.58.0", + "@typescript-eslint/project-service": "8.59.2", + "@typescript-eslint/tsconfig-utils": "8.59.2", + "@typescript-eslint/types": "8.59.2", + "@typescript-eslint/visitor-keys": "8.59.2", "debug": "^4.4.3", "minimatch": "^10.2.2", "semver": "^7.7.3", @@ -2831,16 +3387,16 @@ } }, "node_modules/@typescript-eslint/utils": { - "version": "8.58.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-8.58.0.tgz", - "integrity": "sha512-RfeSqcFeHMHlAWzt4TBjWOAtoW9lnsAGiP3GbaX9uVgTYYrMbVnGONEfUCiSss+xMHFl+eHZiipmA8WkQ7FuNA==", + "version": "8.59.2", + "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-8.59.2.tgz", + "integrity": "sha512-Juw3EinkXqjaffxz6roowvV7GZT/kET5vSKKZT6upl5TXdWkLkYmNPXwDDL2Vkt2DPn0nODIS4egC/0AGxKo/Q==", "dev": true, "license": "MIT", "dependencies": { "@eslint-community/eslint-utils": "^4.9.1", - "@typescript-eslint/scope-manager": "8.58.0", - "@typescript-eslint/types": "8.58.0", - "@typescript-eslint/typescript-estree": "8.58.0" + "@typescript-eslint/scope-manager": "8.59.2", + "@typescript-eslint/types": "8.59.2", + "@typescript-eslint/typescript-estree": "8.59.2" }, "engines": { "node": "^18.18.0 || ^20.9.0 || >=21.1.0" @@ -2855,13 +3411,13 @@ } }, "node_modules/@typescript-eslint/visitor-keys": { - "version": "8.58.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-8.58.0.tgz", - "integrity": "sha512-XJ9UD9+bbDo4a4epraTwG3TsNPeiB9aShrUneAVXy8q4LuwowN+qu89/6ByLMINqvIMeI9H9hOHQtg/ijrYXzQ==", + "version": "8.59.2", + "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-8.59.2.tgz", + "integrity": "sha512-NwjLUnGy8/Zfx23fl50tRC8rYaYnM52xNRYFAXvmiil9yh1+K6aRVQMnzW6gQB/1DLgWt977lYQn7C+wtgXZiA==", "dev": true, "license": "MIT", "dependencies": { - "@typescript-eslint/types": "8.58.0", + "@typescript-eslint/types": "8.59.2", "eslint-visitor-keys": "^5.0.0" }, "engines": { @@ -2910,16 +3466,16 @@ } }, "node_modules/@vitest/expect": { - "version": "4.1.4", - "resolved": "https://registry.npmjs.org/@vitest/expect/-/expect-4.1.4.tgz", - "integrity": "sha512-iPBpra+VDuXmBFI3FMKHSFXp3Gx5HfmSCE8X67Dn+bwephCnQCaB7qWK2ldHa+8ncN8hJU8VTMcxjPpyMkUjww==", + "version": "4.1.5", + "resolved": "https://registry.npmjs.org/@vitest/expect/-/expect-4.1.5.tgz", + "integrity": "sha512-PWBaRY5JoKuRnHlUHfpV/KohFylaDZTupcXN1H9vYryNLOnitSw60Mw9IAE2r67NbwwzBw/Cc/8q9BK3kIX8Kw==", "dev": true, "license": "MIT", "dependencies": { "@standard-schema/spec": "^1.1.0", "@types/chai": "^5.2.2", - "@vitest/spy": "4.1.4", - "@vitest/utils": "4.1.4", + "@vitest/spy": "4.1.5", + "@vitest/utils": "4.1.5", "chai": "^6.2.2", "tinyrainbow": "^3.1.0" }, @@ -2928,13 +3484,13 @@ } }, "node_modules/@vitest/mocker": { - "version": "4.1.4", - "resolved": "https://registry.npmjs.org/@vitest/mocker/-/mocker-4.1.4.tgz", - "integrity": "sha512-R9HTZBhW6yCSGbGQnDnH3QHfJxokKN4KB+Yvk9Q1le7eQNYwiCyKxmLmurSpFy6BzJanSLuEUDrD+j97Q+ZLPg==", + "version": "4.1.5", + "resolved": "https://registry.npmjs.org/@vitest/mocker/-/mocker-4.1.5.tgz", + "integrity": "sha512-/x2EmFC4mT4NNzqvC3fmesuV97w5FC903KPmey4gsnJiMQ3Be1IlDKVaDaG8iqaLFHqJ2FVEkxZk5VmeLjIItw==", "dev": true, "license": "MIT", "dependencies": { - "@vitest/spy": "4.1.4", + "@vitest/spy": "4.1.5", "estree-walker": "^3.0.3", "magic-string": "^0.30.21" }, @@ -2955,9 +3511,9 @@ } }, "node_modules/@vitest/pretty-format": { - "version": "4.1.4", - "resolved": "https://registry.npmjs.org/@vitest/pretty-format/-/pretty-format-4.1.4.tgz", - "integrity": "sha512-ddmDHU0gjEUyEVLxtZa7xamrpIefdEETu3nZjWtHeZX4QxqJ7tRxSteHVXJOcr8jhiLoGAhkK4WJ3WqBpjx42A==", + "version": "4.1.5", + "resolved": "https://registry.npmjs.org/@vitest/pretty-format/-/pretty-format-4.1.5.tgz", + "integrity": "sha512-7I3q6l5qr03dVfMX2wCo9FxwSJbPdwKjy2uu/YPpU3wfHvIL4QHwVRp57OfGrDFeUJ8/8QdfBKIV12FTtLn00g==", "dev": true, "license": "MIT", "dependencies": { @@ -2968,13 +3524,13 @@ } }, "node_modules/@vitest/runner": { - "version": "4.1.4", - "resolved": "https://registry.npmjs.org/@vitest/runner/-/runner-4.1.4.tgz", - "integrity": "sha512-xTp7VZ5aXP5ZJrn15UtJUWlx6qXLnGtF6jNxHepdPHpMfz/aVPx+htHtgcAL2mDXJgKhpoo2e9/hVJsIeFbytQ==", + "version": "4.1.5", + "resolved": "https://registry.npmjs.org/@vitest/runner/-/runner-4.1.5.tgz", + "integrity": "sha512-2D+o7Pr82IEO46YPpoA/YU0neeyr6FTerQb5Ro7BUnBuv6NQtT/kmVnczngiMEBhzgqz2UZYl5gArejsyERDSQ==", "dev": true, "license": "MIT", "dependencies": { - "@vitest/utils": "4.1.4", + "@vitest/utils": "4.1.5", "pathe": "^2.0.3" }, "funding": { @@ -2982,14 +3538,14 @@ } }, "node_modules/@vitest/snapshot": { - "version": "4.1.4", - "resolved": "https://registry.npmjs.org/@vitest/snapshot/-/snapshot-4.1.4.tgz", - "integrity": "sha512-MCjCFgaS8aZz+m5nTcEcgk/xhWv0rEH4Yl53PPlMXOZ1/Ka2VcZU6CJ+MgYCZbcJvzGhQRjVrGQNZqkGPttIKw==", + "version": "4.1.5", + "resolved": "https://registry.npmjs.org/@vitest/snapshot/-/snapshot-4.1.5.tgz", + "integrity": "sha512-zypXEt4KH/XgKGPUz4eC2AvErYx0My5hfL8oDb1HzGFpEk1P62bxSohdyOmvz+d9UJwanI68MKwr2EquOaOgMQ==", "dev": true, "license": "MIT", "dependencies": { - "@vitest/pretty-format": "4.1.4", - "@vitest/utils": "4.1.4", + "@vitest/pretty-format": "4.1.5", + "@vitest/utils": "4.1.5", "magic-string": "^0.30.21", "pathe": "^2.0.3" }, @@ -2998,9 +3554,9 @@ } }, "node_modules/@vitest/spy": { - "version": "4.1.4", - "resolved": "https://registry.npmjs.org/@vitest/spy/-/spy-4.1.4.tgz", - "integrity": "sha512-XxNdAsKW7C+FLydqFJLb5KhJtl3PGCMmYwFRfhvIgxJvLSXhhVI1zM8f1qD3Zg7RCjTSzDVyct6sghs9UEgBEQ==", + "version": "4.1.5", + "resolved": "https://registry.npmjs.org/@vitest/spy/-/spy-4.1.5.tgz", + "integrity": "sha512-2lNOsh6+R2Idnf1TCZqSwYlKN2E/iDlD8sgU59kYVl+OMDmvldO1VDk39smRfpUNwYpNRVn3w4YfuC7KfbBnkQ==", "dev": true, "license": "MIT", "funding": { @@ -3008,13 +3564,13 @@ } }, "node_modules/@vitest/utils": { - "version": "4.1.4", - "resolved": "https://registry.npmjs.org/@vitest/utils/-/utils-4.1.4.tgz", - "integrity": "sha512-13QMT+eysM5uVGa1rG4kegGYNp6cnQcsTc67ELFbhNLQO+vgsygtYJx2khvdt4gVQqSSpC/KT5FZZxUpP3Oatw==", + "version": "4.1.5", + "resolved": "https://registry.npmjs.org/@vitest/utils/-/utils-4.1.5.tgz", + "integrity": "sha512-76wdkrmfXfqGjueGgnb45ITPyUi1ycZ4IHgC2bhPDUfWHklY/q3MdLOAB+TF1e6xfl8NxNY0ZYaPCFNWSsw3Ug==", "dev": true, "license": "MIT", "dependencies": { - "@vitest/pretty-format": "4.1.4", + "@vitest/pretty-format": "4.1.5", "convert-source-map": "^2.0.0", "tinyrainbow": "^3.1.0" }, @@ -3024,6 +3580,8 @@ }, "node_modules/acorn": { "version": "8.16.0", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.16.0.tgz", + "integrity": "sha512-UVJyE9MttOsBQIDKw1skb9nAwQuR5wuGD3+82K6JgJlm/Y+KI92oNsMNGZCYdDsVtRHSak0pcV5Dno5+4jh9sw==", "dev": true, "license": "MIT", "bin": { @@ -3035,6 +3593,8 @@ }, "node_modules/acorn-jsx": { "version": "5.3.2", + "resolved": "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-5.3.2.tgz", + "integrity": "sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==", "dev": true, "license": "MIT", "peerDependencies": { @@ -3042,7 +3602,9 @@ } }, "node_modules/ajv": { - "version": "6.14.0", + "version": "6.15.0", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.15.0.tgz", + "integrity": "sha512-fgFx7Hfoq60ytK2c7DhnF8jIvzYgOMxfugjLOSMHjLIPgenqa7S7oaagATUq99mV6IYvN2tRmC0wnTYX6iPbMw==", "dev": true, "license": "MIT", "dependencies": { @@ -3065,25 +3627,6 @@ "node": ">=8" } }, - "node_modules/ansi-styles": { - "version": "4.3.0", - "dev": true, - "license": "MIT", - "dependencies": { - "color-convert": "^2.0.1" - }, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/chalk/ansi-styles?sponsor=1" - } - }, - "node_modules/argparse": { - "version": "2.0.1", - "dev": true, - "license": "Python-2.0" - }, "node_modules/aria-hidden": { "version": "1.2.6", "license": "MIT", @@ -3113,7 +3656,9 @@ } }, "node_modules/autoprefixer": { - "version": "10.4.27", + "version": "10.5.0", + "resolved": "https://registry.npmjs.org/autoprefixer/-/autoprefixer-10.5.0.tgz", + "integrity": "sha512-FMhOoZV4+qR6aTUALKX2rEqGG+oyATvwBt9IIzVR5rMa2HRWPkxf+P+PAJLD1I/H5/II+HuZcBJYEFBpq39ong==", "dev": true, "funding": [ { @@ -3131,8 +3676,8 @@ ], "license": "MIT", "dependencies": { - "browserslist": "^4.28.1", - "caniuse-lite": "^1.0.30001774", + "browserslist": "^4.28.2", + "caniuse-lite": "^1.0.30001787", "fraction.js": "^5.3.4", "picocolors": "^1.1.1", "postcss-value-parser": "^4.2.0" @@ -3158,7 +3703,9 @@ } }, "node_modules/baseline-browser-mapping": { - "version": "2.10.8", + "version": "2.10.27", + "resolved": "https://registry.npmjs.org/baseline-browser-mapping/-/baseline-browser-mapping-2.10.27.tgz", + "integrity": "sha512-zEs/ufmZoUd7WftKpKyXaT6RFxpQ5Qm9xytKRHvJfxFV9DFJkZph9RvJ1LcOUi0Z1ZVijMte65JbILeV+8QQEA==", "dev": true, "license": "Apache-2.0", "bin": { @@ -3170,6 +3717,8 @@ }, "node_modules/bidi-js": { "version": "1.0.3", + "resolved": "https://registry.npmjs.org/bidi-js/-/bidi-js-1.0.3.tgz", + "integrity": "sha512-RKshQI1R3YQ+n9YJz2QQ147P66ELpa1FQEg20Dk8oW9t2KgLbpDLLp9aGZ7y8WHSshDknG0bknqGw5/tyCs5tw==", "dev": true, "license": "MIT", "dependencies": { @@ -3190,7 +3739,9 @@ } }, "node_modules/browserslist": { - "version": "4.28.1", + "version": "4.28.2", + "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.28.2.tgz", + "integrity": "sha512-48xSriZYYg+8qXna9kwqjIVzuQxi+KYWp2+5nCYnYKPTr0LvD89Jqk2Or5ogxz0NUMfIjhh2lIUX/LyX9B4oIg==", "dev": true, "funding": [ { @@ -3208,11 +3759,11 @@ ], "license": "MIT", "dependencies": { - "baseline-browser-mapping": "^2.9.0", - "caniuse-lite": "^1.0.30001759", - "electron-to-chromium": "^1.5.263", - "node-releases": "^2.0.27", - "update-browserslist-db": "^1.2.0" + "baseline-browser-mapping": "^2.10.12", + "caniuse-lite": "^1.0.30001782", + "electron-to-chromium": "^1.5.328", + "node-releases": "^2.0.36", + "update-browserslist-db": "^1.2.3" }, "bin": { "browserslist": "cli.js" @@ -3221,16 +3772,10 @@ "node": "^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7" } }, - "node_modules/callsites": { - "version": "3.1.0", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=6" - } - }, "node_modules/caniuse-lite": { - "version": "1.0.30001780", + "version": "1.0.30001791", + "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001791.tgz", + "integrity": "sha512-yk0l/YSrOnFZk3UROpDLQD9+kC1l4meK/wed583AXrzoarMGJcbRi2Q4RaUYbKxYAsZ8sWmaSa/DsLmdBeI1vQ==", "dev": true, "funding": [ { @@ -3258,21 +3803,6 @@ "node": ">=18" } }, - "node_modules/chalk": { - "version": "4.1.2", - "dev": true, - "license": "MIT", - "dependencies": { - "ansi-styles": "^4.1.0", - "supports-color": "^7.1.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/chalk/chalk?sponsor=1" - } - }, "node_modules/class-variance-authority": { "version": "0.7.1", "license": "Apache-2.0", @@ -3290,27 +3820,6 @@ "node": ">=6" } }, - "node_modules/color-convert": { - "version": "2.0.1", - "dev": true, - "license": "MIT", - "dependencies": { - "color-name": "~1.1.4" - }, - "engines": { - "node": ">=7.0.0" - } - }, - "node_modules/color-name": { - "version": "1.1.4", - "dev": true, - "license": "MIT" - }, - "node_modules/concat-map": { - "version": "0.0.1", - "dev": true, - "license": "MIT" - }, "node_modules/convert-source-map": { "version": "2.0.0", "dev": true, @@ -3664,7 +4173,9 @@ } }, "node_modules/electron-to-chromium": { - "version": "1.5.313", + "version": "1.5.349", + "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.5.349.tgz", + "integrity": "sha512-QsWVGyRuY07Aqb234QytTfwd5d9AJlfNIQ5wIOl1L+PZDzI9d9+Fn0FRale/QYlFxt/bUnB0/nLd1jFPGxGK1A==", "dev": true, "license": "ISC" }, @@ -3682,11 +4193,13 @@ } }, "node_modules/entities": { - "version": "6.0.1", + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/entities/-/entities-8.0.0.tgz", + "integrity": "sha512-zwfzJecQ/Uej6tusMqwAqU/6KL2XaB2VZ2Jg54Je6ahNBGNH6Ek6g3jjNCF0fG9EWQKGZNddNjU5F1ZQn/sBnA==", "dev": true, "license": "BSD-2-Clause", "engines": { - "node": ">=0.12" + "node": ">=20.19.0" }, "funding": { "url": "https://github.com/fb55/entities?sponsor=1" @@ -3725,31 +4238,30 @@ } }, "node_modules/eslint": { - "version": "9.39.4", + "version": "10.3.0", + "resolved": "https://registry.npmjs.org/eslint/-/eslint-10.3.0.tgz", + "integrity": "sha512-XbEXaRva5cF0ZQB8w6MluHA0kZZfV2DuCMJ3ozyEOHLwDpZX2Lmm/7Pp0xdJmI0GL1W05VH5VwIFHEm1Vcw2gw==", "dev": true, "license": "MIT", "dependencies": { "@eslint-community/eslint-utils": "^4.8.0", - "@eslint-community/regexpp": "^4.12.1", - "@eslint/config-array": "^0.21.2", - "@eslint/config-helpers": "^0.4.2", - "@eslint/core": "^0.17.0", - "@eslint/eslintrc": "^3.3.5", - "@eslint/js": "9.39.4", - "@eslint/plugin-kit": "^0.4.1", + "@eslint-community/regexpp": "^4.12.2", + "@eslint/config-array": "^0.23.5", + "@eslint/config-helpers": "^0.5.5", + "@eslint/core": "^1.2.1", + "@eslint/plugin-kit": "^0.7.1", "@humanfs/node": "^0.16.6", "@humanwhocodes/module-importer": "^1.0.1", "@humanwhocodes/retry": "^0.4.2", "@types/estree": "^1.0.6", "ajv": "^6.14.0", - "chalk": "^4.0.0", "cross-spawn": "^7.0.6", "debug": "^4.3.2", "escape-string-regexp": "^4.0.0", - "eslint-scope": "^8.4.0", - "eslint-visitor-keys": "^4.2.1", - "espree": "^10.4.0", - "esquery": "^1.5.0", + "eslint-scope": "^9.1.2", + "eslint-visitor-keys": "^5.0.1", + "espree": "^11.2.0", + "esquery": "^1.7.0", "esutils": "^2.0.2", "fast-deep-equal": "^3.1.3", "file-entry-cache": "^8.0.0", @@ -3759,8 +4271,7 @@ "imurmurhash": "^0.1.4", "is-glob": "^4.0.0", "json-stable-stringify-without-jsonify": "^1.0.1", - "lodash.merge": "^4.6.2", - "minimatch": "^3.1.5", + "minimatch": "^10.2.4", "natural-compare": "^1.4.0", "optionator": "^0.9.3" }, @@ -3768,7 +4279,7 @@ "eslint": "bin/eslint.js" }, "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + "node": "^20.19.0 || ^22.13.0 || >=24" }, "funding": { "url": "https://eslint.org/donate" @@ -3783,7 +4294,9 @@ } }, "node_modules/eslint-plugin-react-hooks": { - "version": "7.0.1", + "version": "7.1.1", + "resolved": "https://registry.npmjs.org/eslint-plugin-react-hooks/-/eslint-plugin-react-hooks-7.1.1.tgz", + "integrity": "sha512-f2I7Gw6JbvCexzIInuSbZpfdQ44D7iqdWX01FKLvrPgqxoE7oMj8clOfto8U6vYiz4yd5oKu39rRSVOe1zRu0g==", "dev": true, "license": "MIT", "dependencies": { @@ -3797,7 +4310,7 @@ "node": ">=18" }, "peerDependencies": { - "eslint": "^3.0.0 || ^4.0.0 || ^5.0.0 || ^6.0.0 || ^7.0.0 || ^8.0.0-0 || ^9.0.0" + "eslint": "^3.0.0 || ^4.0.0 || ^5.0.0 || ^6.0.0 || ^7.0.0 || ^8.0.0-0 || ^9.0.0 || ^10.0.0" } }, "node_modules/eslint-plugin-react-refresh": { @@ -3809,15 +4322,19 @@ } }, "node_modules/eslint-scope": { - "version": "8.4.0", + "version": "9.1.2", + "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-9.1.2.tgz", + "integrity": "sha512-xS90H51cKw0jltxmvmHy2Iai1LIqrfbw57b79w/J7MfvDfkIkFZ+kj6zC3BjtUwh150HsSSdxXZcsuv72miDFQ==", "dev": true, "license": "BSD-2-Clause", "dependencies": { + "@types/esrecurse": "^4.3.1", + "@types/estree": "^1.0.8", "esrecurse": "^4.3.0", "estraverse": "^5.2.0" }, "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + "node": "^20.19.0 || ^22.13.0 || >=24" }, "funding": { "url": "https://opencollective.com/eslint" @@ -3834,26 +4351,14 @@ "url": "https://opencollective.com/eslint" } }, - "node_modules/eslint/node_modules/balanced-match": { - "version": "1.0.2", - "dev": true, - "license": "MIT" - }, - "node_modules/eslint/node_modules/brace-expansion": { - "version": "1.1.12", - "dev": true, - "license": "MIT", - "dependencies": { - "balanced-match": "^1.0.0", - "concat-map": "0.0.1" - } - }, "node_modules/eslint/node_modules/eslint-visitor-keys": { - "version": "4.2.1", + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-5.0.1.tgz", + "integrity": "sha512-tD40eHxA35h0PEIZNeIjkHoDR4YjjJp34biM0mDvplBe//mB+IHCqHDGV7pxF+7MklTvighcCPPZC7ynWyjdTA==", "dev": true, "license": "Apache-2.0", "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + "node": "^20.19.0 || ^22.13.0 || >=24" }, "funding": { "url": "https://opencollective.com/eslint" @@ -3867,39 +4372,32 @@ "node": ">= 4" } }, - "node_modules/eslint/node_modules/minimatch": { - "version": "3.1.5", - "dev": true, - "license": "ISC", - "dependencies": { - "brace-expansion": "^1.1.7" - }, - "engines": { - "node": "*" - } - }, "node_modules/espree": { - "version": "10.4.0", + "version": "11.2.0", + "resolved": "https://registry.npmjs.org/espree/-/espree-11.2.0.tgz", + "integrity": "sha512-7p3DrVEIopW1B1avAGLuCSh1jubc01H2JHc8B4qqGblmg5gI9yumBgACjWo4JlIc04ufug4xJ3SQI8HkS/Rgzw==", "dev": true, "license": "BSD-2-Clause", "dependencies": { - "acorn": "^8.15.0", + "acorn": "^8.16.0", "acorn-jsx": "^5.3.2", - "eslint-visitor-keys": "^4.2.1" + "eslint-visitor-keys": "^5.0.1" }, "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + "node": "^20.19.0 || ^22.13.0 || >=24" }, "funding": { "url": "https://opencollective.com/eslint" } }, "node_modules/espree/node_modules/eslint-visitor-keys": { - "version": "4.2.1", + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-5.0.1.tgz", + "integrity": "sha512-tD40eHxA35h0PEIZNeIjkHoDR4YjjJp34biM0mDvplBe//mB+IHCqHDGV7pxF+7MklTvighcCPPZC7ynWyjdTA==", "dev": true, "license": "Apache-2.0", "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + "node": "^20.19.0 || ^22.13.0 || >=24" }, "funding": { "url": "https://opencollective.com/eslint" @@ -3918,6 +4416,8 @@ }, "node_modules/esrecurse": { "version": "4.3.0", + "resolved": "https://registry.npmjs.org/esrecurse/-/esrecurse-4.3.0.tgz", + "integrity": "sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag==", "dev": true, "license": "BSD-2-Clause", "dependencies": { @@ -3973,6 +4473,8 @@ }, "node_modules/fast-json-stable-stringify": { "version": "2.1.0", + "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz", + "integrity": "sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==", "dev": true, "license": "MIT" }, @@ -4091,7 +4593,9 @@ } }, "node_modules/globals": { - "version": "14.0.0", + "version": "17.6.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-17.6.0.tgz", + "integrity": "sha512-sepffkT8stwnIYbsMBpoCHJuJM5l98FUF2AnE07hfvE0m/qp3R586hw4jF4uadbhvg1ooIdzuu7CsfD2jzCaNA==", "dev": true, "license": "MIT", "engines": { @@ -4107,14 +4611,6 @@ "integrity": "sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==", "license": "ISC" }, - "node_modules/has-flag": { - "version": "4.0.0", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=8" - } - }, "node_modules/hermes-estree": { "version": "0.25.1", "dev": true, @@ -4155,21 +4651,6 @@ "url": "https://opencollective.com/immer" } }, - "node_modules/import-fresh": { - "version": "3.3.1", - "dev": true, - "license": "MIT", - "dependencies": { - "parent-module": "^1.0.0", - "resolve-from": "^4.0.0" - }, - "engines": { - "node": ">=6" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, "node_modules/imurmurhash": { "version": "0.1.4", "dev": true, @@ -4214,6 +4695,8 @@ }, "node_modules/is-potential-custom-element-name": { "version": "1.0.1", + "resolved": "https://registry.npmjs.org/is-potential-custom-element-name/-/is-potential-custom-element-name-1.0.1.tgz", + "integrity": "sha512-bCYeRA2rVibKZd+s2625gGnGF/t7DSqDs4dP7CrLA1m7jKWz6pps0LpYLJN8Q64HtmPKJ1hrN3nzPNKFEKOUiQ==", "dev": true, "license": "MIT" }, @@ -4234,38 +4717,29 @@ "dev": true, "license": "MIT" }, - "node_modules/js-yaml": { - "version": "4.1.1", - "dev": true, - "license": "MIT", - "dependencies": { - "argparse": "^2.0.1" - }, - "bin": { - "js-yaml": "bin/js-yaml.js" - } - }, "node_modules/jsdom": { - "version": "29.0.1", + "version": "29.1.1", + "resolved": "https://registry.npmjs.org/jsdom/-/jsdom-29.1.1.tgz", + "integrity": "sha512-ECi4Fi2f7BdJtUKTflYRTiaMxIB0O6zfR1fX0GXpUrf6flp8QIYn1UT20YQqdSOfk2dfkCwS8LAFoJDEppNK5Q==", "dev": true, "license": "MIT", "dependencies": { - "@asamuzakjp/css-color": "^5.0.1", - "@asamuzakjp/dom-selector": "^7.0.3", + "@asamuzakjp/css-color": "^5.1.11", + "@asamuzakjp/dom-selector": "^7.1.1", "@bramus/specificity": "^2.4.2", - "@csstools/css-syntax-patches-for-csstree": "^1.1.1", + "@csstools/css-syntax-patches-for-csstree": "^1.1.3", "@exodus/bytes": "^1.15.0", "css-tree": "^3.2.1", "data-urls": "^7.0.0", "decimal.js": "^10.6.0", "html-encoding-sniffer": "^6.0.0", "is-potential-custom-element-name": "^1.0.1", - "lru-cache": "^11.2.7", - "parse5": "^8.0.0", + "lru-cache": "^11.3.5", + "parse5": "^8.0.1", "saxes": "^6.0.0", "symbol-tree": "^3.2.4", "tough-cookie": "^6.0.1", - "undici": "^7.24.5", + "undici": "^7.25.0", "w3c-xmlserializer": "^5.0.0", "webidl-conversions": "^8.0.1", "whatwg-mimetype": "^5.0.0", @@ -4285,7 +4759,9 @@ } }, "node_modules/jsdom/node_modules/lru-cache": { - "version": "11.2.7", + "version": "11.3.6", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-11.3.6.tgz", + "integrity": "sha512-Gf/KoL3C/MlI7Bt0PGI9I+TeTC/I6r/csU58N4BSNc4lppLBeKsOdFYkK+dX0ABDUMJNfCHTyPpzwwO21Awd3A==", "dev": true, "license": "BlueOak-1.0.0", "engines": { @@ -4310,6 +4786,8 @@ }, "node_modules/json-schema-traverse": { "version": "0.4.1", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", + "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==", "dev": true, "license": "MIT" }, @@ -4608,11 +5086,6 @@ "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/lodash.merge": { - "version": "4.6.2", - "dev": true, - "license": "MIT" - }, "node_modules/lru-cache": { "version": "5.1.1", "dev": true, @@ -4622,7 +5095,9 @@ } }, "node_modules/lucide-react": { - "version": "1.7.0", + "version": "1.14.0", + "resolved": "https://registry.npmjs.org/lucide-react/-/lucide-react-1.14.0.tgz", + "integrity": "sha512-+1mdWcfSJVUsaTIjN9zoezmUhfXo5l0vP7ekBMPo3jcS/aIkxHnXqAPsByszMZx/Y8oQBRJxJx5xg+RH3urzxA==", "license": "ISC", "peerDependencies": { "react": "^16.5.1 || ^17.0.0 || ^18.0.0 || ^19.0.0" @@ -4777,23 +5252,14 @@ "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/parent-module": { - "version": "1.0.1", - "dev": true, - "license": "MIT", - "dependencies": { - "callsites": "^3.0.0" - }, - "engines": { - "node": ">=6" - } - }, "node_modules/parse5": { - "version": "8.0.0", + "version": "8.0.1", + "resolved": "https://registry.npmjs.org/parse5/-/parse5-8.0.1.tgz", + "integrity": "sha512-z1e/HMG90obSGeidlli3hj7cbocou0/wa5HacvI3ASx34PecNjNQeaHNo5WIZpWofN9kgkqV1q5YvXe3F0FoPw==", "dev": true, "license": "MIT", "dependencies": { - "entities": "^6.0.0" + "entities": "^8.0.0" }, "funding": { "url": "https://github.com/inikulin/parse5?sponsor=1" @@ -4838,7 +5304,9 @@ } }, "node_modules/postcss": { - "version": "8.5.8", + "version": "8.5.14", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.5.14.tgz", + "integrity": "sha512-SoSL4+OSEtR99LHFZQiJLkT59C5B1amGO1NzTwj7TT1qCUgUO6hxOvzkOYxD+vMrXBM3XJIKzokoERdqQq/Zmg==", "funding": [ { "type": "opencollective", @@ -4916,6 +5384,147 @@ "node": ">=6" } }, + "node_modules/radix-ui": { + "version": "1.4.3", + "resolved": "https://registry.npmjs.org/radix-ui/-/radix-ui-1.4.3.tgz", + "integrity": "sha512-aWizCQiyeAenIdUbqEpXgRA1ya65P13NKn/W8rWkcN0OPkRDxdBVLWnIEDsS2RpwCK2nobI7oMUSmexzTDyAmA==", + "license": "MIT", + "dependencies": { + "@radix-ui/primitive": "1.1.3", + "@radix-ui/react-accessible-icon": "1.1.7", + "@radix-ui/react-accordion": "1.2.12", + "@radix-ui/react-alert-dialog": "1.1.15", + "@radix-ui/react-arrow": "1.1.7", + "@radix-ui/react-aspect-ratio": "1.1.7", + "@radix-ui/react-avatar": "1.1.10", + "@radix-ui/react-checkbox": "1.3.3", + "@radix-ui/react-collapsible": "1.1.12", + "@radix-ui/react-collection": "1.1.7", + "@radix-ui/react-compose-refs": "1.1.2", + "@radix-ui/react-context": "1.1.2", + "@radix-ui/react-context-menu": "2.2.16", + "@radix-ui/react-dialog": "1.1.15", + "@radix-ui/react-direction": "1.1.1", + "@radix-ui/react-dismissable-layer": "1.1.11", + "@radix-ui/react-dropdown-menu": "2.1.16", + "@radix-ui/react-focus-guards": "1.1.3", + "@radix-ui/react-focus-scope": "1.1.7", + "@radix-ui/react-form": "0.1.8", + "@radix-ui/react-hover-card": "1.1.15", + "@radix-ui/react-label": "2.1.7", + "@radix-ui/react-menu": "2.1.16", + "@radix-ui/react-menubar": "1.1.16", + "@radix-ui/react-navigation-menu": "1.2.14", + "@radix-ui/react-one-time-password-field": "0.1.8", + "@radix-ui/react-password-toggle-field": "0.1.3", + "@radix-ui/react-popover": "1.1.15", + "@radix-ui/react-popper": "1.2.8", + "@radix-ui/react-portal": "1.1.9", + "@radix-ui/react-presence": "1.1.5", + "@radix-ui/react-primitive": "2.1.3", + "@radix-ui/react-progress": "1.1.7", + "@radix-ui/react-radio-group": "1.3.8", + "@radix-ui/react-roving-focus": "1.1.11", + "@radix-ui/react-scroll-area": "1.2.10", + "@radix-ui/react-select": "2.2.6", + "@radix-ui/react-separator": "1.1.7", + "@radix-ui/react-slider": "1.3.6", + "@radix-ui/react-slot": "1.2.3", + "@radix-ui/react-switch": "1.2.6", + "@radix-ui/react-tabs": "1.1.13", + "@radix-ui/react-toast": "1.2.15", + "@radix-ui/react-toggle": "1.1.10", + "@radix-ui/react-toggle-group": "1.1.11", + "@radix-ui/react-toolbar": "1.1.11", + "@radix-ui/react-tooltip": "1.2.8", + "@radix-ui/react-use-callback-ref": "1.1.1", + "@radix-ui/react-use-controllable-state": "1.2.2", + "@radix-ui/react-use-effect-event": "0.0.2", + "@radix-ui/react-use-escape-keydown": "1.1.1", + "@radix-ui/react-use-is-hydrated": "0.1.0", + "@radix-ui/react-use-layout-effect": "1.1.1", + "@radix-ui/react-use-size": "1.1.1", + "@radix-ui/react-visually-hidden": "1.2.3" + }, + "peerDependencies": { + "@types/react": "*", + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } + } + }, + "node_modules/radix-ui/node_modules/@radix-ui/react-label": { + "version": "2.1.7", + "resolved": "https://registry.npmjs.org/@radix-ui/react-label/-/react-label-2.1.7.tgz", + "integrity": "sha512-YT1GqPSL8kJn20djelMX7/cTRp/Y9w5IZHvfxQTVHrOqa2yMl7i/UfMqKRU5V7mEyKTrUVgJXhNQPVCG8PBLoQ==", + "license": "MIT", + "dependencies": { + "@radix-ui/react-primitive": "2.1.3" + }, + "peerDependencies": { + "@types/react": "*", + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } + } + }, + "node_modules/radix-ui/node_modules/@radix-ui/react-separator": { + "version": "1.1.7", + "resolved": "https://registry.npmjs.org/@radix-ui/react-separator/-/react-separator-1.1.7.tgz", + "integrity": "sha512-0HEb8R9E8A+jZjvmFCy/J4xhbXy3TV+9XSnGJ3KvTtjlIUy/YQ/p6UYZvi7YbeoeXdyU9+Y3scizK6hkY37baA==", + "license": "MIT", + "dependencies": { + "@radix-ui/react-primitive": "2.1.3" + }, + "peerDependencies": { + "@types/react": "*", + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } + } + }, + "node_modules/radix-ui/node_modules/@radix-ui/react-slot": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/@radix-ui/react-slot/-/react-slot-1.2.3.tgz", + "integrity": "sha512-aeNmHnBxbi2St0au6VBVC7JXFlhLlOnvIIlePNniyUNAClzmtAUEY8/pBiK3iHjufOlwA+c20/8jngo7xcrg8A==", + "license": "MIT", + "dependencies": { + "@radix-ui/react-compose-refs": "1.1.2" + }, + "peerDependencies": { + "@types/react": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, "node_modules/react": { "version": "19.2.5", "resolved": "https://registry.npmjs.org/react/-/react-19.2.5.tgz", @@ -4938,9 +5547,9 @@ } }, "node_modules/react-hook-form": { - "version": "7.72.1", - "resolved": "https://registry.npmjs.org/react-hook-form/-/react-hook-form-7.72.1.tgz", - "integrity": "sha512-RhwBoy2ygeVZje+C+bwJ8g0NjTdBmDlJvAUHTxRjTmSUKPYsKfMphkS2sgEMotsY03bP358yEYlnUeZy//D9Ig==", + "version": "7.75.0", + "resolved": "https://registry.npmjs.org/react-hook-form/-/react-hook-form-7.75.0.tgz", + "integrity": "sha512-Ovv94H+0p3sJ7B9B5QxPuCP1u8V/cHuVGyH55cSwodYDtoJwK+fqk3vjfIgSX59I2U/bU4z0nRJ9HMLpNiWEmw==", "license": "MIT", "engines": { "node": ">=18.0.0" @@ -5023,9 +5632,9 @@ } }, "node_modules/react-resizable-panels": { - "version": "4.9.0", - "resolved": "https://registry.npmjs.org/react-resizable-panels/-/react-resizable-panels-4.9.0.tgz", - "integrity": "sha512-sEl+hA6y9/kxa0aPlrUC+G1lcShAf/PiIjoeC8kWXxa53RfAVplVCIxEl01Nwa4L2iRa5JXBXq1/mI8ch6qOZQ==", + "version": "4.11.0", + "resolved": "https://registry.npmjs.org/react-resizable-panels/-/react-resizable-panels-4.11.0.tgz", + "integrity": "sha512-LPk/AkFDGkg7SsbOyL93ojrE6E7lhrxxDwnYNjfmnSeI6BE7Sje6dB24PXgZk8DeugdeXNk1LO+ohRqIjhxiLw==", "license": "MIT", "peerDependencies": { "react": "^18.0.0 || ^19.0.0", @@ -5033,9 +5642,9 @@ } }, "node_modules/react-router": { - "version": "7.14.1", - "resolved": "https://registry.npmjs.org/react-router/-/react-router-7.14.1.tgz", - "integrity": "sha512-5BCvFskyAAVumqhEKh/iPhLOIkfxcEUz8WqFIARCkMg8hZZzDYX9CtwxXA0e+qT8zAxmMC0x3Ckb9iMONwc5jg==", + "version": "7.14.2", + "resolved": "https://registry.npmjs.org/react-router/-/react-router-7.14.2.tgz", + "integrity": "sha512-yCqNne6I8IB6rVCH7XUvlBK7/QKyqypBFGv+8dj4QBFJiiRX+FG7/nkdAvGElyvVZ/HQP5N19wzteuTARXi5Gw==", "license": "MIT", "dependencies": { "cookie": "^1.0.1", @@ -5055,12 +5664,12 @@ } }, "node_modules/react-router-dom": { - "version": "7.14.1", - "resolved": "https://registry.npmjs.org/react-router-dom/-/react-router-dom-7.14.1.tgz", - "integrity": "sha512-ZkrQuwwhGibjQLqH1eCdyiZyLWglPxzxdl5tgwgKEyCSGC76vmAjleGocRe3J/MLfzMUIKwaFJWpFVJhK3d2xA==", + "version": "7.14.2", + "resolved": "https://registry.npmjs.org/react-router-dom/-/react-router-dom-7.14.2.tgz", + "integrity": "sha512-YZcM5ES8jJSM+KrJ9BdvHHqlnGTg5tH3sC5ChFRj4inosKctdyzBDhOyyHdGk597q2OT6NTrCA1OvB/YDwfekQ==", "license": "MIT", "dependencies": { - "react-router": "7.14.1" + "react-router": "7.14.2" }, "engines": { "node": ">=20.0.0" @@ -5151,6 +5760,8 @@ }, "node_modules/require-from-string": { "version": "2.0.2", + "resolved": "https://registry.npmjs.org/require-from-string/-/require-from-string-2.0.2.tgz", + "integrity": "sha512-Xf0nWe6RseziFMu+Ap9biiUbmplq6S9/p+7w7YXP/JBHhrUDDUhwa+vANyubuqfZWTveU//DYVGsDG7RKL/vEw==", "dev": true, "license": "MIT", "engines": { @@ -5161,23 +5772,15 @@ "version": "5.1.1", "license": "MIT" }, - "node_modules/resolve-from": { - "version": "4.0.0", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=4" - } - }, "node_modules/rolldown": { - "version": "1.0.0-rc.15", - "resolved": "https://registry.npmjs.org/rolldown/-/rolldown-1.0.0-rc.15.tgz", - "integrity": "sha512-Ff31guA5zT6WjnGp0SXw76X6hzGRk/OQq2hE+1lcDe+lJdHSgnSX6nK3erbONHyCbpSj9a9E+uX/OvytZoWp2g==", + "version": "1.0.0-rc.17", + "resolved": "https://registry.npmjs.org/rolldown/-/rolldown-1.0.0-rc.17.tgz", + "integrity": "sha512-ZrT53oAKrtA4+YtBWPQbtPOxIbVDbxT0orcYERKd63VJTF13zPcgXTvD4843L8pcsI7M6MErt8QtON6lrB9tyA==", "dev": true, "license": "MIT", "dependencies": { - "@oxc-project/types": "=0.124.0", - "@rolldown/pluginutils": "1.0.0-rc.15" + "@oxc-project/types": "=0.127.0", + "@rolldown/pluginutils": "1.0.0-rc.17" }, "bin": { "rolldown": "bin/cli.mjs" @@ -5186,27 +5789,27 @@ "node": "^20.19.0 || >=22.12.0" }, "optionalDependencies": { - "@rolldown/binding-android-arm64": "1.0.0-rc.15", - "@rolldown/binding-darwin-arm64": "1.0.0-rc.15", - "@rolldown/binding-darwin-x64": "1.0.0-rc.15", - "@rolldown/binding-freebsd-x64": "1.0.0-rc.15", - "@rolldown/binding-linux-arm-gnueabihf": "1.0.0-rc.15", - "@rolldown/binding-linux-arm64-gnu": "1.0.0-rc.15", - "@rolldown/binding-linux-arm64-musl": "1.0.0-rc.15", - "@rolldown/binding-linux-ppc64-gnu": "1.0.0-rc.15", - "@rolldown/binding-linux-s390x-gnu": "1.0.0-rc.15", - "@rolldown/binding-linux-x64-gnu": "1.0.0-rc.15", - "@rolldown/binding-linux-x64-musl": "1.0.0-rc.15", - "@rolldown/binding-openharmony-arm64": "1.0.0-rc.15", - "@rolldown/binding-wasm32-wasi": "1.0.0-rc.15", - "@rolldown/binding-win32-arm64-msvc": "1.0.0-rc.15", - "@rolldown/binding-win32-x64-msvc": "1.0.0-rc.15" + "@rolldown/binding-android-arm64": "1.0.0-rc.17", + "@rolldown/binding-darwin-arm64": "1.0.0-rc.17", + "@rolldown/binding-darwin-x64": "1.0.0-rc.17", + "@rolldown/binding-freebsd-x64": "1.0.0-rc.17", + "@rolldown/binding-linux-arm-gnueabihf": "1.0.0-rc.17", + "@rolldown/binding-linux-arm64-gnu": "1.0.0-rc.17", + "@rolldown/binding-linux-arm64-musl": "1.0.0-rc.17", + "@rolldown/binding-linux-ppc64-gnu": "1.0.0-rc.17", + "@rolldown/binding-linux-s390x-gnu": "1.0.0-rc.17", + "@rolldown/binding-linux-x64-gnu": "1.0.0-rc.17", + "@rolldown/binding-linux-x64-musl": "1.0.0-rc.17", + "@rolldown/binding-openharmony-arm64": "1.0.0-rc.17", + "@rolldown/binding-wasm32-wasi": "1.0.0-rc.17", + "@rolldown/binding-win32-arm64-msvc": "1.0.0-rc.17", + "@rolldown/binding-win32-x64-msvc": "1.0.0-rc.17" } }, "node_modules/rolldown/node_modules/@rolldown/pluginutils": { - "version": "1.0.0-rc.15", - "resolved": "https://registry.npmjs.org/@rolldown/pluginutils/-/pluginutils-1.0.0-rc.15.tgz", - "integrity": "sha512-UromN0peaE53IaBRe9W7CjrZgXl90fqGpK+mIZbA3qSTeYqg3pqpROBdIPvOG3F5ereDHNwoHBI2e50n1BDr1g==", + "version": "1.0.0-rc.17", + "resolved": "https://registry.npmjs.org/@rolldown/pluginutils/-/pluginutils-1.0.0-rc.17.tgz", + "integrity": "sha512-n8iosDOt6Ig1UhJ2AYqoIhHWh/isz0xpicHTzpKBeotdVsTEcxsSA/i3EVM7gQAj0rU27OLAxCjzlj15IWY7bg==", "dev": true, "license": "MIT" }, @@ -5268,6 +5871,16 @@ "dev": true, "license": "ISC" }, + "node_modules/sonner": { + "version": "2.0.7", + "resolved": "https://registry.npmjs.org/sonner/-/sonner-2.0.7.tgz", + "integrity": "sha512-W6ZN4p58k8aDKA4XPcx2hpIQXBRAgyiWVkYhT7CvK6D3iAu7xjvVyhQHg2/iaKJZ1XVJ4r7XuwGL+WGEK37i9w==", + "license": "MIT", + "peerDependencies": { + "react": "^18.0.0 || ^19.0.0 || ^19.0.0-rc", + "react-dom": "^18.0.0 || ^19.0.0 || ^19.0.0-rc" + } + }, "node_modules/source-map-js": { "version": "1.2.1", "license": "BSD-3-Clause", @@ -5300,28 +5913,6 @@ "node": ">=8" } }, - "node_modules/strip-json-comments": { - "version": "3.1.1", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/supports-color": { - "version": "7.2.0", - "dev": true, - "license": "MIT", - "dependencies": { - "has-flag": "^4.0.0" - }, - "engines": { - "node": ">=8" - } - }, "node_modules/symbol-tree": { "version": "3.2.4", "dev": true, @@ -5379,12 +5970,14 @@ } }, "node_modules/tinyglobby": { - "version": "0.2.15", + "version": "0.2.16", + "resolved": "https://registry.npmjs.org/tinyglobby/-/tinyglobby-0.2.16.tgz", + "integrity": "sha512-pn99VhoACYR8nFHhxqix+uvsbXineAasWm5ojXoN8xEwK5Kd3/TrhNn1wByuD52UxWRLy8pu+kRMniEi6Eq9Zg==", "dev": true, "license": "MIT", "dependencies": { "fdir": "^6.5.0", - "picomatch": "^4.0.3" + "picomatch": "^4.0.4" }, "engines": { "node": ">=12.0.0" @@ -5470,9 +6063,9 @@ } }, "node_modules/typescript": { - "version": "6.0.2", - "resolved": "https://registry.npmjs.org/typescript/-/typescript-6.0.2.tgz", - "integrity": "sha512-bGdAIrZ0wiGDo5l8c++HWtbaNCWTS4UTv7RaTH/ThVIgjkveJt83m74bBHMJkuCbslY8ixgLBVZJIOiQlQTjfQ==", + "version": "6.0.3", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-6.0.3.tgz", + "integrity": "sha512-y2TvuxSZPDyQakkFRPZHKFm+KKVqIisdg9/CZwm9ftvKXLP8NRWj38/ODjNbr43SsoXqNuAisEf1GdCxqWcdBw==", "dev": true, "license": "Apache-2.0", "bin": { @@ -5484,7 +6077,9 @@ } }, "node_modules/undici": { - "version": "7.24.6", + "version": "7.25.0", + "resolved": "https://registry.npmjs.org/undici/-/undici-7.25.0.tgz", + "integrity": "sha512-xXnp4kTyor2Zq+J1FfPI6Eq3ew5h6Vl0F/8d9XU5zZQf1tX9s2Su1/3PiMmUANFULpmksxkClamIZcaUqryHsQ==", "dev": true, "license": "MIT", "engines": { @@ -5492,7 +6087,9 @@ } }, "node_modules/undici-types": { - "version": "7.18.2", + "version": "7.19.2", + "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-7.19.2.tgz", + "integrity": "sha512-qYVnV5OEm2AW8cJMCpdV20CDyaN3g0AjDlOGf1OW4iaDEx8MwdtChUp4zu4H0VP3nDRF/8RKWH+IPp9uW0YGZg==", "dev": true, "license": "MIT" }, @@ -5527,6 +6124,8 @@ }, "node_modules/uri-js": { "version": "4.4.1", + "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.4.1.tgz", + "integrity": "sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==", "dev": true, "license": "BSD-2-Clause", "dependencies": { @@ -5600,17 +6199,17 @@ } }, "node_modules/vite": { - "version": "8.0.8", - "resolved": "https://registry.npmjs.org/vite/-/vite-8.0.8.tgz", - "integrity": "sha512-dbU7/iLVa8KZALJyLOBOQ88nOXtNG8vxKuOT4I2mD+Ya70KPceF4IAmDsmU0h1Qsn5bPrvsY9HJstCRh3hG6Uw==", + "version": "8.0.10", + "resolved": "https://registry.npmjs.org/vite/-/vite-8.0.10.tgz", + "integrity": "sha512-rZuUu9j6J5uotLDs+cAA4O5H4K1SfPliUlQwqa6YEwSrWDZzP4rhm00oJR5snMewjxF5V/K3D4kctsUTsIU9Mw==", "dev": true, "license": "MIT", "dependencies": { "lightningcss": "^1.32.0", "picomatch": "^4.0.4", - "postcss": "^8.5.8", - "rolldown": "1.0.0-rc.15", - "tinyglobby": "^0.2.15" + "postcss": "^8.5.10", + "rolldown": "1.0.0-rc.17", + "tinyglobby": "^0.2.16" }, "bin": { "vite": "bin/vite.js" @@ -5678,19 +6277,19 @@ } }, "node_modules/vitest": { - "version": "4.1.4", - "resolved": "https://registry.npmjs.org/vitest/-/vitest-4.1.4.tgz", - "integrity": "sha512-tFuJqTxKb8AvfyqMfnavXdzfy3h3sWZRWwfluGbkeR7n0HUev+FmNgZ8SDrRBTVrVCjgH5cA21qGbCffMNtWvg==", + "version": "4.1.5", + "resolved": "https://registry.npmjs.org/vitest/-/vitest-4.1.5.tgz", + "integrity": "sha512-9Xx1v3/ih3m9hN+SbfkUyy0JAs72ap3r7joc87XL6jwF0jGg6mFBvQ1SrwaX+h8BlkX6Hz9shdd1uo6AF+ZGpg==", "dev": true, "license": "MIT", "dependencies": { - "@vitest/expect": "4.1.4", - "@vitest/mocker": "4.1.4", - "@vitest/pretty-format": "4.1.4", - "@vitest/runner": "4.1.4", - "@vitest/snapshot": "4.1.4", - "@vitest/spy": "4.1.4", - "@vitest/utils": "4.1.4", + "@vitest/expect": "4.1.5", + "@vitest/mocker": "4.1.5", + "@vitest/pretty-format": "4.1.5", + "@vitest/runner": "4.1.5", + "@vitest/snapshot": "4.1.5", + "@vitest/spy": "4.1.5", + "@vitest/utils": "4.1.5", "es-module-lexer": "^2.0.0", "expect-type": "^1.3.0", "magic-string": "^0.30.21", @@ -5718,12 +6317,12 @@ "@edge-runtime/vm": "*", "@opentelemetry/api": "^1.9.0", "@types/node": "^20.0.0 || ^22.0.0 || >=24.0.0", - "@vitest/browser-playwright": "4.1.4", - "@vitest/browser-preview": "4.1.4", - "@vitest/browser-webdriverio": "4.1.4", - "@vitest/coverage-istanbul": "4.1.4", - "@vitest/coverage-v8": "4.1.4", - "@vitest/ui": "4.1.4", + "@vitest/browser-playwright": "4.1.5", + "@vitest/browser-preview": "4.1.5", + "@vitest/browser-webdriverio": "4.1.5", + "@vitest/coverage-istanbul": "4.1.5", + "@vitest/coverage-v8": "4.1.5", + "@vitest/ui": "4.1.5", "happy-dom": "*", "jsdom": "*", "vite": "^6.0.0 || ^7.0.0 || ^8.0.0" @@ -5874,7 +6473,9 @@ } }, "node_modules/zod": { - "version": "4.3.6", + "version": "4.4.3", + "resolved": "https://registry.npmjs.org/zod/-/zod-4.4.3.tgz", + "integrity": "sha512-ytENFjIJFl2UwYglde2jchW2Hwm4GJFLDiSXWdTrJQBIN9Fcyp7n4DhxJEiWNAJMV1/BqWfW/kkg71UDcHJyTQ==", "license": "MIT", "funding": { "url": "https://github.com/sponsors/colinhacks" diff --git a/ui/package.json b/ui/package.json index 8f97e34d0..886f7f886 100644 --- a/ui/package.json +++ b/ui/package.json @@ -27,19 +27,6 @@ "@kalamdb/client": "file:../link/sdks/typescript/client", "@kalamdb/orm": "file:../link/sdks/typescript/orm", "@monaco-editor/react": "^4.7.0", - "@radix-ui/react-context-menu": "^2.2.16", - "@radix-ui/react-dialog": "^1.1.15", - "@radix-ui/react-dropdown-menu": "^2.1.16", - "@radix-ui/react-icons": "^1.3.2", - "@radix-ui/react-label": "^2.1.8", - "@radix-ui/react-scroll-area": "^1.2.10", - "@radix-ui/react-select": "^2.2.6", - "@radix-ui/react-separator": "^1.1.8", - "@radix-ui/react-slot": "^1.2.4", - "@radix-ui/react-switch": "^1.2.6", - "@radix-ui/react-tabs": "^1.1.13", - "@radix-ui/react-toast": "^1.2.15", - "@radix-ui/react-tooltip": "^1.2.8", "@reduxjs/toolkit": "^2.11.2", "@tailwindcss/postcss": "^4.2.4", "@tanstack/react-table": "^8.21.3", @@ -47,36 +34,40 @@ "clsx": "^2.1.1", "drizzle-orm": "^0.45.2", "fast-deep-equal": "^3.1.3", - "lucide-react": "^1.7.0", + "lucide-react": "^1.14.0", + "radix-ui": "^1.4.3", "react": "^19.2.5", "react-dom": "^19.2.5", - "react-hook-form": "^7.72.1", + "react-hook-form": "^7.75.0", "react-redux": "^9.2.0", - "react-resizable-panels": "^4.9.0", - "react-router-dom": "^7.14.1", + "react-resizable-panels": "^4.11.0", + "react-router-dom": "^7.14.2", "recharts": "^3.8.1", + "sonner": "^2.0.7", "tailwind-merge": "^3.5.0", "tailwindcss-animate": "^1.0.7", - "zod": "^4.3.6" + "zod": "^4.4.3" }, "devDependencies": { + "@eslint/js": "^10.0.1", "@testing-library/jest-dom": "^6.9.1", "@testing-library/react": "^16.3.2", - "@types/node": "^25.5.2", + "@types/node": "^25.6.0", "@types/react": "^19.2.14", "@types/react-dom": "^19.2.3", - "@typescript-eslint/eslint-plugin": "^8.58.0", - "@typescript-eslint/parser": "^8.58.0", + "@typescript-eslint/eslint-plugin": "^8.59.2", + "@typescript-eslint/parser": "^8.59.2", "@vitejs/plugin-react": "^6.0.1", - "autoprefixer": "^10.4.27", - "eslint": "^9.39.4", - "eslint-plugin-react-hooks": "^7.0.1", + "autoprefixer": "^10.5.0", + "eslint": "^10.3.0", + "eslint-plugin-react-hooks": "^7.1.1", "eslint-plugin-react-refresh": "^0.5.2", - "jsdom": "^29.0.1", - "postcss": "^8.5.8", - "tailwindcss": "^4.2.2", - "typescript": "^6.0.2", - "vite": "^8.0.8", - "vitest": "^4.1.4" + "globals": "^17.6.0", + "jsdom": "^29.1.1", + "postcss": "^8.5.14", + "tailwindcss": "^4.2.4", + "typescript": "^6.0.3", + "vite": "^8.0.10", + "vitest": "^4.1.5" } } diff --git a/ui/src/components/sql-studio-v2/preview/StudioResultsGrid.tsx b/ui/src/components/sql-studio-v2/preview/StudioResultsGrid.tsx index 946a5de31..22a255b8a 100644 --- a/ui/src/components/sql-studio-v2/preview/StudioResultsGrid.tsx +++ b/ui/src/components/sql-studio-v2/preview/StudioResultsGrid.tsx @@ -581,10 +581,10 @@ export function StudioResultsGrid({ onValueChange={(value) => onResultViewChange(value as SqlStudioResultView)} className="h-full shrink-0" > - + Results {hasUnseenResults && ( @@ -593,7 +593,7 @@ export function StudioResultsGrid({ Log ({logCount}) {hasUnseenLogs && ( diff --git a/ui/src/components/sql-studio-v2/table-editor/EditorSidebar.tsx b/ui/src/components/sql-studio-v2/table-editor/EditorSidebar.tsx index 1279657e4..d0c706d9c 100644 --- a/ui/src/components/sql-studio-v2/table-editor/EditorSidebar.tsx +++ b/ui/src/components/sql-studio-v2/table-editor/EditorSidebar.tsx @@ -236,7 +236,7 @@ export function EditorSidebar({ schema, defaultNamespace = "default", onSchemaRe {namespaces.length > 0 ? ( + ) +} -const Input = React.forwardRef( - ({ className, type, ...props }, ref) => { - return ( - - ); - } -); -Input.displayName = "Input"; - -export { Input }; +export { Input } diff --git a/ui/src/components/ui/resizable.tsx b/ui/src/components/ui/resizable.tsx index d46e23d54..8b139cc74 100644 --- a/ui/src/components/ui/resizable.tsx +++ b/ui/src/components/ui/resizable.tsx @@ -1,43 +1,48 @@ -import { Group, Panel, Separator } from "react-resizable-panels" +import * as ResizablePrimitive from "react-resizable-panels" import { cn } from "@/lib/utils" -import { DragHandleDots2Icon } from "@radix-ui/react-icons" -const ResizablePanelGroup = ({ +function ResizablePanelGroup({ className, ...props -}: React.ComponentProps) => ( - -) +}: ResizablePrimitive.GroupProps) { + return ( + + ) +} -const ResizablePanel = Panel +function ResizablePanel({ ...props }: ResizablePrimitive.PanelProps) { + return +} -const ResizableHandle = ({ +function ResizableHandle({ withHandle, className, ...props -}: React.ComponentProps & { +}: ResizablePrimitive.SeparatorProps & { withHandle?: boolean -}) => ( - div]:rotate-90", - className - )} - {...props} - > - {withHandle && ( -
- -
- )} -
-) +}) { + return ( + div]:rotate-90", + className + )} + {...props} + > + {withHandle && ( +
+ )} + + ) +} -export { ResizablePanelGroup, ResizablePanel, ResizableHandle } +export { ResizableHandle, ResizablePanel, ResizablePanelGroup } diff --git a/ui/src/components/ui/scroll-area.tsx b/ui/src/components/ui/scroll-area.tsx index 020a39a8c..facbbe7d8 100644 --- a/ui/src/components/ui/scroll-area.tsx +++ b/ui/src/components/ui/scroll-area.tsx @@ -1,48 +1,55 @@ "use client" import * as React from "react" -import * as ScrollAreaPrimitive from "@radix-ui/react-scroll-area" +import { ScrollArea as ScrollAreaPrimitive } from "radix-ui" import { cn } from "@/lib/utils" -const ScrollArea = React.forwardRef< - React.ElementRef, - React.ComponentPropsWithoutRef ->(({ className, children, ...props }, ref) => ( - - - {children} - - - - -)) -ScrollArea.displayName = ScrollAreaPrimitive.Root.displayName +function ScrollArea({ + className, + children, + ...props +}: React.ComponentProps) { + return ( + + + {children} + + + + + ) +} -const ScrollBar = React.forwardRef< - React.ElementRef, - React.ComponentPropsWithoutRef ->(({ className, orientation = "vertical", ...props }, ref) => ( - - - -)) -ScrollBar.displayName = ScrollAreaPrimitive.ScrollAreaScrollbar.displayName +function ScrollBar({ + className, + orientation = "vertical", + ...props +}: React.ComponentProps) { + return ( + + + + ) +} export { ScrollArea, ScrollBar } diff --git a/ui/src/components/ui/select.tsx b/ui/src/components/ui/select.tsx index fe56d4d3a..871460c99 100644 --- a/ui/src/components/ui/select.tsx +++ b/ui/src/components/ui/select.tsx @@ -1,158 +1,193 @@ import * as React from "react" -import * as SelectPrimitive from "@radix-ui/react-select" -import { Check, ChevronDown, ChevronUp } from "lucide-react" +import { Select as SelectPrimitive } from "radix-ui" import { cn } from "@/lib/utils" +import { ChevronDownIcon, CheckIcon, ChevronUpIcon } from "lucide-react" -const Select = SelectPrimitive.Root - -const SelectGroup = SelectPrimitive.Group - -const SelectValue = SelectPrimitive.Value - -const SelectTrigger = React.forwardRef< - React.ElementRef, - React.ComponentPropsWithoutRef ->(({ className, children, ...props }, ref) => ( - span]:line-clamp-1", - className - )} - {...props} - > - {children} - - - - -)) -SelectTrigger.displayName = SelectPrimitive.Trigger.displayName +function Select({ + ...props +}: React.ComponentProps) { + return +} -const SelectScrollUpButton = React.forwardRef< - React.ElementRef, - React.ComponentPropsWithoutRef ->(({ className, ...props }, ref) => ( - - - -)) -SelectScrollUpButton.displayName = SelectPrimitive.ScrollUpButton.displayName +function SelectGroup({ + className, + ...props +}: React.ComponentProps) { + return ( + + ) +} -const SelectScrollDownButton = React.forwardRef< - React.ElementRef, - React.ComponentPropsWithoutRef ->(({ className, ...props }, ref) => ( - - - -)) -SelectScrollDownButton.displayName = - SelectPrimitive.ScrollDownButton.displayName +function SelectValue({ + ...props +}: React.ComponentProps) { + return +} -const SelectContent = React.forwardRef< - React.ElementRef, - React.ComponentPropsWithoutRef ->(({ className, children, position = "popper", ...props }, ref) => ( - - & { + size?: "sm" | "default" +}) { + return ( + span]:line-clamp-1 [&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg:not([class*='size-'])]:size-4", className )} - position={position} {...props} > - - + + + + ) +} + +function SelectContent({ + className, + children, + position = "popper", + ...props +}: React.ComponentProps) { + return ( + + - {children} - - - - -)) -SelectContent.displayName = SelectPrimitive.Content.displayName + + + {children} + + + + + ) +} + +function SelectLabel({ + className, + ...props +}: React.ComponentProps) { + return ( + + ) +} -const SelectLabel = React.forwardRef< - React.ElementRef, - React.ComponentPropsWithoutRef ->(({ className, ...props }, ref) => ( - -)) -SelectLabel.displayName = SelectPrimitive.Label.displayName +function SelectItem({ + className, + children, + ...props +}: React.ComponentProps) { + return ( + + + + + + + {children} + + ) +} -const SelectItem = React.forwardRef< - React.ElementRef, - React.ComponentPropsWithoutRef ->(({ className, children, ...props }, ref) => ( - - - - - - +function SelectSeparator({ + className, + ...props +}: React.ComponentProps) { + return ( + + ) +} - {children} - -)) -SelectItem.displayName = SelectPrimitive.Item.displayName +function SelectScrollUpButton({ + className, + ...props +}: React.ComponentProps) { + return ( + + + + ) +} -const SelectSeparator = React.forwardRef< - React.ElementRef, - React.ComponentPropsWithoutRef ->(({ className, ...props }, ref) => ( - -)) -SelectSeparator.displayName = SelectPrimitive.Separator.displayName +function SelectScrollDownButton({ + className, + ...props +}: React.ComponentProps) { + return ( + + + + ) +} export { Select, - SelectGroup, - SelectValue, - SelectTrigger, SelectContent, - SelectLabel, + SelectGroup, SelectItem, - SelectSeparator, - SelectScrollUpButton, + SelectLabel, SelectScrollDownButton, + SelectScrollUpButton, + SelectSeparator, + SelectTrigger, + SelectValue, } diff --git a/ui/src/components/ui/sheet.tsx b/ui/src/components/ui/sheet.tsx index 6ab58c6e2..85e21188c 100644 --- a/ui/src/components/ui/sheet.tsx +++ b/ui/src/components/ui/sheet.tsx @@ -1,130 +1,140 @@ -import * as React from "react"; -import * as SheetPrimitive from "@radix-ui/react-dialog"; -import { cva, type VariantProps } from "class-variance-authority"; -import { X } from "lucide-react"; +import * as React from "react" +import { Dialog as SheetPrimitive } from "radix-ui" -import { cn } from "@/lib/utils"; +import { cn } from "@/lib/utils" +import { Button } from "@/components/ui/button" +import { XIcon } from "lucide-react" -const Sheet = SheetPrimitive.Root; -const SheetTrigger = SheetPrimitive.Trigger; -const SheetClose = SheetPrimitive.Close; -const SheetPortal = SheetPrimitive.Portal; +function Sheet({ ...props }: React.ComponentProps) { + return +} -const SheetOverlay = React.forwardRef< - React.ElementRef, - React.ComponentPropsWithoutRef ->(({ className, ...props }, ref) => ( - -)); -SheetOverlay.displayName = SheetPrimitive.Overlay.displayName; +function SheetTrigger({ + ...props +}: React.ComponentProps) { + return +} -const sheetVariants = cva( - "fixed z-50 gap-4 bg-background p-0 shadow-lg transition ease-in-out data-[state=closed]:duration-200 data-[state=open]:duration-300 data-[state=open]:animate-in data-[state=closed]:animate-out", - { - variants: { - side: { - top: "inset-x-0 top-0 border-b data-[state=closed]:slide-out-to-top data-[state=open]:slide-in-from-top", - bottom: - "inset-x-0 bottom-0 border-t data-[state=closed]:slide-out-to-bottom data-[state=open]:slide-in-from-bottom", - left: "inset-y-0 left-0 h-full w-3/4 border-r data-[state=closed]:slide-out-to-left data-[state=open]:slide-in-from-left sm:max-w-sm", - right: - "inset-y-0 right-0 h-full w-full border-l data-[state=closed]:slide-out-to-right data-[state=open]:slide-in-from-right sm:max-w-[560px]", - }, - }, - defaultVariants: { - side: "right", - }, - }, -); +function SheetClose({ + ...props +}: React.ComponentProps) { + return +} -interface SheetContentProps - extends React.ComponentPropsWithoutRef, - VariantProps {} +function SheetPortal({ + ...props +}: React.ComponentProps) { + return +} -const SheetContent = React.forwardRef< - React.ElementRef, - SheetContentProps ->(({ side = "right", className, children, ...props }, ref) => ( - - - ) { + return ( + - {children} - - - Close - - - -)); -SheetContent.displayName = SheetPrimitive.Content.displayName; + /> + ) +} -const SheetHeader = ({ +function SheetContent({ className, + children, + side = "right", + showCloseButton = true, ...props -}: React.HTMLAttributes) => ( -
-); -SheetHeader.displayName = "SheetHeader"; +}: React.ComponentProps & { + side?: "top" | "right" | "bottom" | "left" + showCloseButton?: boolean +}) { + return ( + + + + {children} + {showCloseButton && ( + + + + )} + + + ) +} + +function SheetHeader({ className, ...props }: React.ComponentProps<"div">) { + return ( +
+ ) +} -const SheetFooter = ({ +function SheetFooter({ className, ...props }: React.ComponentProps<"div">) { + return ( +
+ ) +} + +function SheetTitle({ className, ...props -}: React.HTMLAttributes) => ( -
-); -SheetFooter.displayName = "SheetFooter"; - -const SheetTitle = React.forwardRef< - React.ElementRef, - React.ComponentPropsWithoutRef ->(({ className, ...props }, ref) => ( - -)); -SheetTitle.displayName = SheetPrimitive.Title.displayName; +}: React.ComponentProps) { + return ( + + ) +} -const SheetDescription = React.forwardRef< - React.ElementRef, - React.ComponentPropsWithoutRef ->(({ className, ...props }, ref) => ( - -)); -SheetDescription.displayName = SheetPrimitive.Description.displayName; +function SheetDescription({ + className, + ...props +}: React.ComponentProps) { + return ( + + ) +} export { Sheet, - SheetPortal, - SheetOverlay, SheetTrigger, SheetClose, SheetContent, @@ -132,4 +142,4 @@ export { SheetFooter, SheetTitle, SheetDescription, -}; +} diff --git a/ui/src/components/ui/sonner.tsx b/ui/src/components/ui/sonner.tsx new file mode 100644 index 000000000..2b3b8ac37 --- /dev/null +++ b/ui/src/components/ui/sonner.tsx @@ -0,0 +1,40 @@ +import type { CSSProperties } from "react"; +import { + CircleCheckIcon, + InfoIcon, + Loader2Icon, + OctagonXIcon, + TriangleAlertIcon, +} from "lucide-react"; +import { Toaster as Sonner, type ToasterProps } from "sonner"; + +function Toaster(props: ToasterProps) { + return ( + , + info: , + warning: , + error: , + loading: , + }} + style={ + { + "--normal-bg": "var(--popover)", + "--normal-text": "var(--popover-foreground)", + "--normal-border": "var(--border)", + "--border-radius": "var(--radius)", + } as CSSProperties + } + toastOptions={{ + classNames: { + toast: "cn-toast", + }, + }} + {...props} + /> + ); +} + +export { Toaster }; \ No newline at end of file diff --git a/ui/src/components/ui/switch.tsx b/ui/src/components/ui/switch.tsx index 455c23b6c..1ca9db2a9 100644 --- a/ui/src/components/ui/switch.tsx +++ b/ui/src/components/ui/switch.tsx @@ -1,27 +1,33 @@ +"use client" + import * as React from "react" -import * as SwitchPrimitives from "@radix-ui/react-switch" +import { Switch as SwitchPrimitive } from "radix-ui" import { cn } from "@/lib/utils" -const Switch = React.forwardRef< - React.ElementRef, - React.ComponentPropsWithoutRef ->(({ className, ...props }, ref) => ( - - & { + size?: "sm" | "default" +}) { + return ( + - -)) -Switch.displayName = SwitchPrimitives.Root.displayName + {...props} + > + + + ) +} export { Switch } diff --git a/ui/src/components/ui/table.tsx b/ui/src/components/ui/table.tsx index 7f3502f8b..29a6b0add 100644 --- a/ui/src/components/ui/table.tsx +++ b/ui/src/components/ui/table.tsx @@ -2,108 +2,105 @@ import * as React from "react" import { cn } from "@/lib/utils" -const Table = React.forwardRef< - HTMLTableElement, - React.HTMLAttributes ->(({ className, ...props }, ref) => ( -
- ) { + return ( +
+
+ + ) +} + +function TableHeader({ className, ...props }: React.ComponentProps<"thead">) { + return ( + - -)) -Table.displayName = "Table" - -const TableHeader = React.forwardRef< - HTMLTableSectionElement, - React.HTMLAttributes ->(({ className, ...props }, ref) => ( - -)) -TableHeader.displayName = "TableHeader" + ) +} -const TableBody = React.forwardRef< - HTMLTableSectionElement, - React.HTMLAttributes ->(({ className, ...props }, ref) => ( - -)) -TableBody.displayName = "TableBody" +function TableBody({ className, ...props }: React.ComponentProps<"tbody">) { + return ( + + ) +} -const TableFooter = React.forwardRef< - HTMLTableSectionElement, - React.HTMLAttributes ->(({ className, ...props }, ref) => ( - tr]:last:border-b-0", - className - )} - {...props} - /> -)) -TableFooter.displayName = "TableFooter" +function TableFooter({ className, ...props }: React.ComponentProps<"tfoot">) { + return ( + tr]:last:border-b-0", + className + )} + {...props} + /> + ) +} -const TableRow = React.forwardRef< - HTMLTableRowElement, - React.HTMLAttributes ->(({ className, ...props }, ref) => ( - -)) -TableRow.displayName = "TableRow" +function TableRow({ className, ...props }: React.ComponentProps<"tr">) { + return ( + + ) +} -const TableHead = React.forwardRef< - HTMLTableCellElement, - React.ThHTMLAttributes ->(({ className, ...props }, ref) => ( -
-)) -TableHead.displayName = "TableHead" +function TableHead({ className, ...props }: React.ComponentProps<"th">) { + return ( + + ) +} -const TableCell = React.forwardRef< - HTMLTableCellElement, - React.TdHTMLAttributes ->(({ className, ...props }, ref) => ( - -)) -TableCell.displayName = "TableCell" +function TableCell({ className, ...props }: React.ComponentProps<"td">) { + return ( + + ) +} -const TableCaption = React.forwardRef< - HTMLTableCaptionElement, - React.HTMLAttributes ->(({ className, ...props }, ref) => ( -
-)) -TableCaption.displayName = "TableCaption" +function TableCaption({ + className, + ...props +}: React.ComponentProps<"caption">) { + return ( + + ) +} export { Table, diff --git a/ui/src/components/ui/tabs.tsx b/ui/src/components/ui/tabs.tsx index 85d83beab..006f4c237 100644 --- a/ui/src/components/ui/tabs.tsx +++ b/ui/src/components/ui/tabs.tsx @@ -1,53 +1,89 @@ +"use client" + import * as React from "react" -import * as TabsPrimitive from "@radix-ui/react-tabs" +import { cva, type VariantProps } from "class-variance-authority" +import { Tabs as TabsPrimitive } from "radix-ui" import { cn } from "@/lib/utils" -const Tabs = TabsPrimitive.Root - -const TabsList = React.forwardRef< - React.ElementRef, - React.ComponentPropsWithoutRef ->(({ className, ...props }, ref) => ( - -)) -TabsList.displayName = TabsPrimitive.List.displayName - -const TabsTrigger = React.forwardRef< - React.ElementRef, - React.ComponentPropsWithoutRef ->(({ className, ...props }, ref) => ( - -)) -TabsTrigger.displayName = TabsPrimitive.Trigger.displayName - -const TabsContent = React.forwardRef< - React.ElementRef, - React.ComponentPropsWithoutRef ->(({ className, ...props }, ref) => ( - -)) -TabsContent.displayName = TabsPrimitive.Content.displayName - -export { Tabs, TabsList, TabsTrigger, TabsContent } +function Tabs({ + className, + orientation = "horizontal", + ...props +}: React.ComponentProps) { + return ( + + ) +} + +const tabsListVariants = cva( + "group/tabs-list inline-flex items-center justify-center text-muted-foreground", + { + variants: { + variant: { + default: "h-9 rounded-md bg-muted p-1", + line: "h-full gap-5 border-b border-border bg-transparent p-0", + }, + }, + defaultVariants: { + variant: "default", + }, + } +) + +function TabsList({ + className, + variant = "default", + ...props +}: React.ComponentProps & + VariantProps) { + return ( + + ) +} + +function TabsTrigger({ + className, + ...props +}: React.ComponentProps) { + return ( + + ) +} + +function TabsContent({ + className, + ...props +}: React.ComponentProps) { + return ( + + ) +} + +export { Tabs, TabsList, TabsTrigger, TabsContent, tabsListVariants } diff --git a/ui/src/components/ui/textarea.tsx b/ui/src/components/ui/textarea.tsx index 4d858bb6b..909da381c 100644 --- a/ui/src/components/ui/textarea.tsx +++ b/ui/src/components/ui/textarea.tsx @@ -2,21 +2,17 @@ import * as React from "react" import { cn } from "@/lib/utils" -const Textarea = React.forwardRef< - HTMLTextAreaElement, - React.ComponentProps<"textarea"> ->(({ className, ...props }, ref) => { +function Textarea({ className, ...props }: React.ComponentProps<"textarea">) { return (