diff --git a/Cargo.lock b/Cargo.lock index 508a3a05..a50d623e 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -700,6 +700,7 @@ dependencies = [ "fxhash", "itertools 0.12.1", "loro 0.16.12", + "loro 0.16.12 (git+https://github.com/loro-dev/loro.git?tag=loro-crdt@1.0.0-alpha.4)", "loro 0.16.2 (git+https://github.com/loro-dev/loro.git?tag=loro-crdt@0.16.7)", "loro 0.16.2 (git+https://github.com/loro-dev/loro.git?rev=90470658435ec4c62b5af59ebb82fe9e1f5aa761)", "num_cpus", @@ -1058,13 +1059,27 @@ dependencies = [ "loro-common 0.16.12", "loro-delta 0.16.12", "loro-internal 0.16.12", - "loro-kv-store", + "loro-kv-store 0.16.2", "pretty_assertions", "rand", "serde_json", "tracing", ] +[[package]] +name = "loro" +version = "0.16.12" +source = "git+https://github.com/loro-dev/loro.git?tag=loro-crdt@1.0.0-alpha.4#9bfe97bce4912c6dc8439817497d18423a0e8cb7" +dependencies = [ + "enum-as-inner 0.6.0", + "generic-btree", + "loro-common 0.16.12 (git+https://github.com/loro-dev/loro.git?tag=loro-crdt@1.0.0-alpha.4)", + "loro-delta 0.16.12 (git+https://github.com/loro-dev/loro.git?tag=loro-crdt@1.0.0-alpha.4)", + "loro-internal 0.16.12 (git+https://github.com/loro-dev/loro.git?tag=loro-crdt@1.0.0-alpha.4)", + "loro-kv-store 0.16.2 (git+https://github.com/loro-dev/loro.git?tag=loro-crdt@1.0.0-alpha.4)", + "tracing", +] + [[package]] name = "loro-common" version = "0.16.2" @@ -1116,6 +1131,24 @@ dependencies = [ "wasm-bindgen", ] +[[package]] +name = "loro-common" +version = "0.16.12" +source = "git+https://github.com/loro-dev/loro.git?tag=loro-crdt@1.0.0-alpha.4#9bfe97bce4912c6dc8439817497d18423a0e8cb7" +dependencies = [ + "arbitrary", + "enum-as-inner 0.6.0", + "fxhash", + "leb128", + "loro-rle 0.16.12 (git+https://github.com/loro-dev/loro.git?tag=loro-crdt@1.0.0-alpha.4)", + "nonmax", + "serde", + "serde_columnar", + "serde_json", + "string_cache", + "thiserror", +] + [[package]] name = "loro-delta" version = "0.16.2" @@ -1156,6 +1189,18 @@ dependencies = [ "tracing-subscriber", ] +[[package]] +name = "loro-delta" +version = "0.16.12" +source = "git+https://github.com/loro-dev/loro.git?tag=loro-crdt@1.0.0-alpha.4#9bfe97bce4912c6dc8439817497d18423a0e8cb7" +dependencies = [ + "arrayvec", + "enum-as-inner 0.5.1", + "generic-btree", + "heapless 0.8.0", + "tracing", +] + [[package]] name = "loro-ffi" version = "0.16.2" @@ -1262,7 +1307,7 @@ dependencies = [ "leb128", "loro-common 0.16.12", "loro-delta 0.16.12", - "loro-kv-store", + "loro-kv-store 0.16.2", "loro-rle 0.16.12", "loro_fractional_index 0.16.12", "md5", @@ -1291,6 +1336,47 @@ dependencies = [ "zstd", ] +[[package]] +name = "loro-internal" +version = "0.16.12" +source = "git+https://github.com/loro-dev/loro.git?tag=loro-crdt@1.0.0-alpha.4#9bfe97bce4912c6dc8439817497d18423a0e8cb7" +dependencies = [ + "append-only-bytes", + "arref", + "bytes", + "either", + "ensure-cov", + "enum-as-inner 0.6.0", + "enum_dispatch", + "fxhash", + "generic-btree", + "getrandom", + "im", + "itertools 0.12.1", + "leb128", + "loro-common 0.16.12 (git+https://github.com/loro-dev/loro.git?tag=loro-crdt@1.0.0-alpha.4)", + "loro-delta 0.16.12 (git+https://github.com/loro-dev/loro.git?tag=loro-crdt@1.0.0-alpha.4)", + "loro-kv-store 0.16.2 (git+https://github.com/loro-dev/loro.git?tag=loro-crdt@1.0.0-alpha.4)", + "loro-rle 0.16.12 (git+https://github.com/loro-dev/loro.git?tag=loro-crdt@1.0.0-alpha.4)", + "loro_fractional_index 0.16.12 (git+https://github.com/loro-dev/loro.git?tag=loro-crdt@1.0.0-alpha.4)", + "md5", + "nonmax", + "num", + "num-derive", + "num-traits", + "once_cell", + "postcard", + "pretty_assertions", + "rand", + "serde", + "serde_columnar", + "serde_json", + "smallvec", + "thiserror", + "tracing", + "xxhash-rust", +] + [[package]] name = "loro-kv-store" version = "0.16.2" @@ -1309,6 +1395,22 @@ dependencies = [ "xxhash-rust", ] +[[package]] +name = "loro-kv-store" +version = "0.16.2" +source = "git+https://github.com/loro-dev/loro.git?tag=loro-crdt@1.0.0-alpha.4#9bfe97bce4912c6dc8439817497d18423a0e8cb7" +dependencies = [ + "bytes", + "ensure-cov", + "fxhash", + "loro-common 0.16.12 (git+https://github.com/loro-dev/loro.git?tag=loro-crdt@1.0.0-alpha.4)", + "lz4_flex", + "once_cell", + "quick_cache", + "tracing", + "xxhash-rust", +] + [[package]] name = "loro-rle" version = "0.16.2" @@ -1352,6 +1454,19 @@ dependencies = [ "static_assertions", ] +[[package]] +name = "loro-rle" +version = "0.16.12" +source = "git+https://github.com/loro-dev/loro.git?tag=loro-crdt@1.0.0-alpha.4#9bfe97bce4912c6dc8439817497d18423a0e8cb7" +dependencies = [ + "append-only-bytes", + "arref", + "enum-as-inner 0.6.0", + "fxhash", + "num", + "smallvec", +] + [[package]] name = "loro-thunderdome" version = "0.6.2" @@ -1411,6 +1526,18 @@ dependencies = [ "smallvec", ] +[[package]] +name = "loro_fractional_index" +version = "0.16.12" +source = "git+https://github.com/loro-dev/loro.git?tag=loro-crdt@1.0.0-alpha.4#9bfe97bce4912c6dc8439817497d18423a0e8cb7" +dependencies = [ + "imbl", + "once_cell", + "rand", + "serde", + "smallvec", +] + [[package]] name = "lz4_flex" version = "0.11.3" diff --git a/crates/fuzz/Cargo.toml b/crates/fuzz/Cargo.toml index 07339a54..e85f622f 100644 --- a/crates/fuzz/Cargo.toml +++ b/crates/fuzz/Cargo.toml @@ -24,6 +24,7 @@ rayon = "1.10.0" bytes = "1" ensure-cov = { workspace = true } pretty_assertions = "1.4.0" +loro-alpha-4 = { git = "https://github.com/loro-dev/loro.git", tag = "loro-crdt@1.0.0-alpha.4", package = "loro" } [dev-dependencies] ctor = "0.2" diff --git a/crates/fuzz/tests/compatibility.rs b/crates/fuzz/tests/compatibility.rs index ce95bedd..c92d13d1 100644 --- a/crates/fuzz/tests/compatibility.rs +++ b/crates/fuzz/tests/compatibility.rs @@ -149,3 +149,286 @@ fn snapshot_from_016_can_be_imported_in_cur_version() { doc_current.get_deep_value().to_json() ); } + +/// Macro to generate random operations on a LoroDoc. +/// +/// This macro creates a series of random operations on various container types +/// within a LoroDoc. It's useful for testing and fuzzing purposes. +/// +/// # Parameters +/// +/// * `$doc` - A reference to a `loro::LoroDoc` instance. +/// * `$seed` - A `u64` value used to seed the random number generator. +/// * `$len` - A `usize` value specifying the number of random operations to perform. +/// +/// # Example +/// +/// ``` +/// let doc = loro::LoroDoc::new(); +/// gen_random_ops!(doc, 12345, 100); +/// ``` +#[macro_export] +macro_rules! gen_random_ops { + ($doc:expr, $seed:expr, $len:expr) => {{ + use rand::rngs::StdRng; + use rand::seq::SliceRandom; + use rand::{Rng, SeedableRng}; + + let mut rng = StdRng::seed_from_u64($seed); + let containers = ["text", "map", "list", "tree", "movable_list"]; + + for _ in 0..$len { + let container = containers.choose(&mut rng).unwrap(); + match *container { + "text" => { + let text = $doc.get_text("text"); + let pos = rng.gen_range(0..=text.len_unicode()); + let content = (0..5).map(|_| rng.gen::()).collect::(); + if rng.gen_bool(0.7) { + text.insert(pos, &content).unwrap_or_default(); + } else { + let del_len = rng.gen_range(0..=text.len_unicode().saturating_sub(pos)); + text.delete(pos, del_len).unwrap_or_default(); + } + } + "map" => { + let map = $doc.get_map("map"); + let key = format!("key_{}", rng.gen::()); + if rng.gen_bool(0.7) { + let value = format!("value_{}", rng.gen::()); + map.insert(&key, value).unwrap(); + } else if !map.is_empty() { + let v = map.get_value(); + let existing_key = v + .as_map() + .unwrap() + .keys() + .nth(rng.gen_range(0..map.len())) + .unwrap(); + map.delete(&existing_key).unwrap(); + } + } + "list" => { + let list = $doc.get_list("list"); + let pos = rng.gen_range(0..=list.len()); + if rng.gen_bool(0.7) { + let value = rng.gen::(); + list.insert(pos, value).unwrap(); + } else if !list.is_empty() { + list.delete(pos, 1).unwrap_or_default(); + } + } + "tree" => { + let tree = $doc.get_tree("tree"); + tree.enable_fractional_index(0); + let nodes: Vec<_> = tree.nodes(); + if nodes.is_empty() { + tree.create(None).unwrap(); + } else { + let node = nodes.choose(&mut rng).unwrap(); + match rng.gen_range(0..3) { + 0 => { + tree.create(Some(*node)).unwrap(); + } + 1 if !tree.is_node_deleted(node).unwrap() => { + tree.delete(*node).unwrap_or_default(); + } + _ => { + if let Some(sibling) = nodes.choose(&mut rng) { + if sibling != node + && !tree.is_node_deleted(sibling).unwrap() + && !tree.is_node_deleted(node).unwrap() + { + tree.mov_before(*node, *sibling).unwrap_or_default(); + } + } + } + } + } + } + "movable_list" => { + let movable_list = $doc.get_movable_list("movable_list"); + let pos = rng.gen_range(0..=movable_list.len()); + match rng.gen_range(0..3) { + 0 => { + let value = rng.gen::(); + movable_list.insert(pos, value).unwrap(); + } + 1 => { + if !movable_list.is_empty() { + movable_list.delete(pos, 1).unwrap_or_default(); + } + } + 2 => { + if !movable_list.is_empty() { + let from = rng.gen_range(0..movable_list.len()); + let to = rng.gen_range(0..=movable_list.len()); + movable_list.mov(from, to).unwrap_or_default(); + } + } + _ => unreachable!("unreachable movable list op"), + } + } + _ => unreachable!("unreachable container type"), + } + } + $doc.commit(); + }}; +} +#[ctor::ctor] +fn init() { + dev_utils::setup_test_log(); +} + +mod compatibility_with_10_alpha_4 { + use super::*; + use loro_alpha_4::{self, ToJson}; + + #[test] + fn test_shallow_snapshot() { + let doc1 = loro::LoroDoc::new(); + doc1.set_peer_id(1).unwrap(); + gen_random_ops!(doc1, 12345, 100); + let snapshot = doc1 + .export(loro::ExportMode::shallow_snapshot_since(ID::new(1, 50))) + .unwrap(); + + let doc2 = loro_alpha_4::LoroDoc::new(); + doc2.import(&snapshot).unwrap(); + assert_eq!( + doc1.get_deep_value().to_json_value(), + doc2.get_deep_value().to_json_value() + ); + assert_eq!( + doc2.shallow_since_frontiers().encode(), + loro::Frontiers::from_id(ID::new(1, 50)).encode() + ); + + gen_random_ops!(doc2, 12345, 100); + let snapshot = doc2 + .export(loro_alpha_4::ExportMode::all_updates()) + .unwrap(); + doc1.import(&snapshot).unwrap(); + assert_eq!( + doc1.get_deep_value().to_json_value(), + doc2.get_deep_value().to_json_value() + ); + } + + #[test] + fn test_shallow_snapshot_mirrored() { + let doc1 = loro_alpha_4::LoroDoc::new(); + doc1.set_peer_id(1).unwrap(); + gen_random_ops!(doc1, 1234, 100); + let snapshot = doc1 + .export(loro_alpha_4::ExportMode::shallow_snapshot_since( + loro_alpha_4::ID::new(1, 50), + )) + .unwrap(); + + let doc2 = loro::LoroDoc::new(); + doc2.import(&snapshot).unwrap(); + assert_eq!( + doc1.get_deep_value().to_json_value(), + doc2.get_deep_value().to_json_value() + ); + assert_eq!( + doc2.shallow_since_frontiers().encode(), + loro_alpha_4::Frontiers::from_id(loro_alpha_4::ID::new(1, 50)).encode() + ); + + gen_random_ops!(doc2, 1234, 100); + let snapshot = doc2.export(loro::ExportMode::all_updates()).unwrap(); + doc1.import(&snapshot).unwrap(); + assert_eq!( + doc1.get_deep_value().to_json_value(), + doc2.get_deep_value().to_json_value() + ); + } + + #[test] + fn test_snapshot() { + let doc1 = loro_alpha_4::LoroDoc::new(); + doc1.set_peer_id(1).unwrap(); + gen_random_ops!(doc1, 1234, 100); + let snapshot = doc1.export(loro_alpha_4::ExportMode::Snapshot).unwrap(); + + let doc2 = loro::LoroDoc::new(); + doc2.import(&snapshot).unwrap(); + assert_eq!( + doc1.get_deep_value().to_json_value(), + doc2.get_deep_value().to_json_value() + ); + + gen_random_ops!(doc2, 5678, 100); + let snapshot = doc2.export(loro::ExportMode::Snapshot).unwrap(); + doc1.import(&snapshot).unwrap(); + assert_eq!( + doc1.get_deep_value().to_json_value(), + doc2.get_deep_value().to_json_value() + ); + + let updates = + serde_json::to_value(doc1.export_json_updates(&Default::default(), &doc1.oplog_vv())) + .unwrap(); + let updates_b = + serde_json::to_value(doc2.export_json_updates(&Default::default(), &doc2.oplog_vv())) + .unwrap(); + assert_eq!(updates, updates_b); + } + + #[test] + fn test_updates() { + let doc1 = loro_alpha_4::LoroDoc::new(); + let doc2 = Arc::new(loro::LoroDoc::new()); + let doc2_clone = doc2.clone(); + doc1.set_peer_id(1).unwrap(); + doc1.subscribe_local_update(Box::new(move |updates| { + doc2_clone.import(updates).unwrap(); + true + })) + .detach(); + + for i in 0..5 { + gen_random_ops!(doc1, i, 10); + assert_eq!( + doc1.get_deep_value().to_json_value(), + doc2.get_deep_value().to_json_value() + ); + } + } + + #[test] + fn test_update_in_range() { + let doc1 = loro_alpha_4::LoroDoc::new(); + let doc2 = loro::LoroDoc::new(); + + // Generate some initial content + gen_random_ops!(doc1, 1234, 50); + let version = doc1.oplog_vv(); + let doc1_value = doc1.get_deep_value().to_json_value(); + gen_random_ops!(doc1, 1234, 50); + let updates = doc1 + .export(loro_alpha_4::ExportMode::updates_till(&version)) + .unwrap(); + + doc2.import(&updates).unwrap(); + assert_eq!(doc1_value, doc2.get_deep_value().to_json_value()); + } + + #[test] + fn test_json_updates() { + let doc1 = loro_alpha_4::LoroDoc::new(); + let doc2 = loro::LoroDoc::new(); + + gen_random_ops!(doc1, 0, 1000); + let updates = + serde_json::to_string(&doc1.export_json_updates(&Default::default(), &doc1.oplog_vv())) + .unwrap(); + doc2.import_json_updates(updates).unwrap(); + assert_eq!( + doc1.get_deep_value().to_json_value(), + doc2.get_deep_value().to_json_value() + ); + } +} diff --git a/crates/loro-internal/src/diff_calc/tree.rs b/crates/loro-internal/src/diff_calc/tree.rs index b671082c..183145a3 100644 --- a/crates/loro-internal/src/diff_calc/tree.rs +++ b/crates/loro-internal/src/diff_calc/tree.rs @@ -505,7 +505,7 @@ impl TreeCacheForDiff { self.is_ancestor_of(maybe_ancestor, parent) } TreeParentId::Deleted | TreeParentId::Root => false, - TreeParentId::Unexist => unreachable!(), + TreeParentId::Unexist => false, } } diff --git a/crates/loro-internal/src/handler.rs b/crates/loro-internal/src/handler.rs index 19a8c523..96917eb5 100644 --- a/crates/loro-internal/src/handler.rs +++ b/crates/loro-internal/src/handler.rs @@ -3702,6 +3702,51 @@ impl MapHandler { Ok(()) } + + pub fn keys(&self) -> impl Iterator + '_ { + let mut keys: Vec = Vec::with_capacity(self.len()); + match &self.inner { + MaybeDetached::Detached(m) => { + let m = m.try_lock().unwrap(); + keys = m.value.keys().map(|x| x.as_str().into()).collect(); + } + MaybeDetached::Attached(a) => { + a.with_state(|state| { + for (k, _) in state.as_map_state().unwrap().iter() { + keys.push(k.clone()); + } + }); + } + } + + keys.into_iter() + } + + pub fn values(&self) -> impl Iterator + '_ { + let mut values: Vec = Vec::with_capacity(self.len()); + match &self.inner { + MaybeDetached::Detached(m) => { + let m = m.try_lock().unwrap(); + values = m.value.values().cloned().collect(); + } + MaybeDetached::Attached(a) => { + a.with_state(|state| { + for (_, v) in state.as_map_state().unwrap().iter() { + let value = match &v.value { + Some(LoroValue::Container(container_id)) => { + ValueOrHandler::Handler(create_handler(a, container_id.clone())) + } + Some(value) => ValueOrHandler::Value(value.clone()), + None => continue, + }; + values.push(value); + } + }); + } + } + + values.into_iter() + } } #[inline(always)] diff --git a/crates/loro-internal/src/handler/tree.rs b/crates/loro-internal/src/handler/tree.rs index 38da8f58..e3b2413a 100644 --- a/crates/loro-internal/src/handler/tree.rs +++ b/crates/loro-internal/src/handler/tree.rs @@ -288,6 +288,12 @@ impl TreeHandler { pub(crate) fn delete_with_txn(&self, txn: &mut Transaction, target: TreeID) -> LoroResult<()> { let inner = self.inner.try_attached_state()?; + let index = match self.get_index_by_tree_id(&target) { + Some(i) => i, + None => { + return Err(LoroTreeError::TreeNodeDeletedOrNotExist(target).into()); + } + }; txn.apply_local_op( inner.container_idx, crate::op::RawOpContent::Tree(Arc::new(TreeOp::Delete { target })), @@ -295,7 +301,7 @@ impl TreeHandler { target, action: TreeExternalDiff::Delete { old_parent: self.get_node_parent(&target).unwrap(), - old_index: self.get_index_by_tree_id(&target).unwrap(), + old_index: index }, }]), &inner.state, @@ -993,4 +999,17 @@ impl TreeHandler { MaybeDetached::Attached(a) => a.is_deleted(), } } + + pub fn is_empty(&self) -> bool { + match &self.inner { + MaybeDetached::Detached(t) => { + let t = t.try_lock().unwrap(); + t.value.map.is_empty() + } + MaybeDetached::Attached(a) => a.with_state(|state| { + let a = state.as_tree_state().unwrap(); + a.is_empty() + }), + } + } } diff --git a/crates/loro-internal/src/state/tree_state.rs b/crates/loro-internal/src/state/tree_state.rs index 0a008c3a..76426f2e 100644 --- a/crates/loro-internal/src/state/tree_state.rs +++ b/crates/loro-internal/src/state/tree_state.rs @@ -1013,6 +1013,13 @@ impl TreeState { } } } + + pub fn is_empty(&self) -> bool { + match self.children.get(&TreeParentId::Root) { + Some(c) => c.len() == 0, + None => true, + } + } } pub(crate) enum FractionalIndexGenResult { diff --git a/crates/loro/src/lib.rs b/crates/loro/src/lib.rs index e867fc5b..45772e0e 100644 --- a/crates/loro/src/lib.rs +++ b/crates/loro/src/lib.rs @@ -2,6 +2,7 @@ #![warn(missing_docs)] #![warn(missing_debug_implementations)] use event::{DiffEvent, Subscriber}; +use loro_common::InternalString; pub use loro_internal::cursor::CannotFindRelativePosition; use loro_internal::cursor::Cursor; use loro_internal::cursor::PosQueryResult; @@ -1281,6 +1282,19 @@ impl LoroMap { pub fn clear(&self) -> LoroResult<()> { self.handler.clear() } + + /// Get the keys of the map. + pub fn keys(&self) -> impl Iterator + '_ { + self.handler.keys() + } + + /// Get the values of the map. + pub fn values(&self) -> impl Iterator + '_ { + self.handler.values().map(|v| match v { + ValueOrHandler::Value(v) => ValueOrContainer::Value(v), + ValueOrHandler::Handler(c) => ValueOrContainer::Container(Container::from_handler(c)), + }) + } } impl Default for LoroMap { @@ -1920,6 +1934,13 @@ impl LoroTree { pub fn disable_fractional_index(&self) { self.handler.disable_fractional_index(); } + + /// Whether the tree is empty. + /// + #[inline] + pub fn is_empty(&self) -> bool { + self.handler.is_empty() + } } impl Default for LoroTree { diff --git a/loro-js/package.json b/loro-js/package.json index ab9e51c3..963e9c19 100644 --- a/loro-js/package.json +++ b/loro-js/package.json @@ -36,6 +36,7 @@ "esbuild": "^0.18.20", "eslint": "^8.46.0", "loro-crdt-old": "npm:loro-crdt@=0.16.0", + "loro-crdt-alpha-4": "npm:loro-crdt@=1.0.0-alpha.4", "prettier": "^3.0.0", "rollup": "^3.20.1", "rollup-plugin-dts": "^5.3.0", diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 543177be..ab35bf14 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -19,10 +19,10 @@ importers: devDependencies: vite-plugin-top-level-await: specifier: ^1.2.2 - version: 1.4.1(vite@4.5.3) + version: 1.4.1(rollup@4.17.2)(vite@5.2.11) vite-plugin-wasm: specifier: ^3.1.0 - version: 3.3.0(vite@4.5.3) + version: 3.3.0(vite@5.2.11) examples/loro-quill: dependencies: @@ -44,7 +44,7 @@ importers: version: 1.3.10 '@vitejs/plugin-vue': specifier: ^4.1.0 - version: 4.6.2(vite@4.5.3)(vue@3.4.27) + version: 4.6.2(vite@4.5.3)(vue@3.4.27(typescript@5.4.5)) typescript: specifier: ^5.2.0 version: 5.4.5 @@ -53,7 +53,7 @@ importers: version: 4.5.3 vite-plugin-top-level-await: specifier: ^1.3.0 - version: 1.4.1(vite@4.5.3) + version: 1.4.1(rollup@4.17.2)(vite@4.5.3) vite-plugin-wasm: specifier: ^3.2.2 version: 3.3.0(vite@4.5.3) @@ -82,6 +82,9 @@ importers: eslint: specifier: ^8.46.0 version: 8.57.0 + loro-crdt-alpha-4: + specifier: npm:loro-crdt@=1.0.0-alpha.4 + version: loro-crdt@1.0.0-alpha.4 loro-crdt-old: specifier: npm:loro-crdt@=0.16.0 version: loro-crdt@0.16.0 @@ -1669,9 +1672,15 @@ packages: loro-crdt@0.16.0: resolution: {integrity: sha512-U/fwXPfe3GjE96tP97qzIjGoDOz5K/zSNPs1QZ7ZO4pqOAkjkLhBifSYZWW2v1t7ufFgUa4XqXpS1pn7Hyze2A==} + loro-crdt@1.0.0-alpha.4: + resolution: {integrity: sha512-WFVf/goGbiC9wmA7GNf9Fmdwry5hJq/CcQkXjoEp4QC9OYMUGm6QqKsrI7M4q05e2l7JeTc0RU858C7FRtg7qw==} + loro-wasm@0.16.0: resolution: {integrity: sha512-2puF09ppACoUwMf9+6BkuYlogY+qZqqStq6RbYYXMhL8Uxrf8DXJdmLA+XGgI4suxXh39jvt6XfwdafqcUuu4A==} + loro-wasm@1.0.0-alpha.4: + resolution: {integrity: sha512-M1Bwh1PQQUFwdAldpSGZD3wl5D/6gQkbTC6aRoC8SjIxv0mgVzibp9sw9DXnolwoJ/Abd4hWeCz2sOvYOzw+Hg==} + loupe@2.3.7: resolution: {integrity: sha512-zSMINGVYkdpYSOBmLi0D1Uo7JU9nVdQKrHxC8eYlV+9YKK9WePqAlL7lSlorG/U2Fw1w0hTBmaa/jrQ3UbPHtA==} @@ -2896,15 +2905,19 @@ snapshots: is-builtin-module: 3.2.1 is-module: 1.0.0 resolve: 1.22.8 + optionalDependencies: rollup: 3.29.4 - '@rollup/plugin-virtual@3.0.2': {} + '@rollup/plugin-virtual@3.0.2(rollup@4.17.2)': + optionalDependencies: + rollup: 4.17.2 '@rollup/pluginutils@5.1.0(rollup@3.29.4)': dependencies: '@types/estree': 1.0.5 estree-walker: 2.0.2 picomatch: 2.3.1 + optionalDependencies: rollup: 3.29.4 '@rollup/rollup-android-arm-eabi@4.17.2': @@ -3033,6 +3046,7 @@ snapshots: '@typescript-eslint/visitor-keys': 6.21.0 debug: 4.3.4 eslint: 8.57.0 + optionalDependencies: typescript: 5.4.5 transitivePeerDependencies: - supports-color @@ -3054,6 +3068,7 @@ snapshots: minimatch: 9.0.3 semver: 7.6.2 ts-api-utils: 1.3.0(typescript@5.4.5) + optionalDependencies: typescript: 5.4.5 transitivePeerDependencies: - supports-color @@ -3065,7 +3080,7 @@ snapshots: '@ungap/structured-clone@1.2.0': {} - '@vitejs/plugin-vue@4.6.2(vite@4.5.3)(vue@3.4.27)': + '@vitejs/plugin-vue@4.6.2(vite@4.5.3)(vue@3.4.27(typescript@5.4.5))': dependencies: vite: 4.5.3 vue: 3.4.27(typescript@5.4.5) @@ -3163,8 +3178,9 @@ snapshots: minimatch: 9.0.4 muggle-string: 0.3.1 path-browserify: 1.0.1 - typescript: 5.4.5 vue-template-compiler: 2.7.16 + optionalDependencies: + typescript: 5.4.5 '@vue/reactivity@3.4.27': dependencies: @@ -3181,7 +3197,7 @@ snapshots: '@vue/shared': 3.4.27 csstype: 3.1.3 - '@vue/server-renderer@3.4.27(vue@3.4.27)': + '@vue/server-renderer@3.4.27(vue@3.4.27(typescript@5.4.5))': dependencies: '@vue/compiler-ssr': 3.4.27 '@vue/shared': 3.4.27 @@ -4159,8 +4175,14 @@ snapshots: dependencies: loro-wasm: 0.16.0 + loro-crdt@1.0.0-alpha.4: + dependencies: + loro-wasm: 1.0.0-alpha.4 + loro-wasm@0.16.0: {} + loro-wasm@1.0.0-alpha.4: {} + loupe@2.3.7: dependencies: get-func-name: 2.0.2 @@ -4836,9 +4858,9 @@ snapshots: - supports-color - terser - vite-plugin-top-level-await@1.4.1(vite@4.5.3): + vite-plugin-top-level-await@1.4.1(rollup@4.17.2)(vite@4.5.3): dependencies: - '@rollup/plugin-virtual': 3.0.2 + '@rollup/plugin-virtual': 3.0.2(rollup@4.17.2) '@swc/core': 1.5.5 uuid: 9.0.1 vite: 4.5.3 @@ -4846,10 +4868,24 @@ snapshots: - '@swc/helpers' - rollup + vite-plugin-top-level-await@1.4.1(rollup@4.17.2)(vite@5.2.11): + dependencies: + '@rollup/plugin-virtual': 3.0.2(rollup@4.17.2) + '@swc/core': 1.5.5 + uuid: 9.0.1 + vite: 5.2.11 + transitivePeerDependencies: + - '@swc/helpers' + - rollup + vite-plugin-wasm@3.3.0(vite@4.5.3): dependencies: vite: 4.5.3 + vite-plugin-wasm@3.3.0(vite@5.2.11): + dependencies: + vite: 5.2.11 + vite@4.5.3: dependencies: esbuild: 0.18.20 @@ -4872,7 +4908,6 @@ snapshots: '@vitest/runner': 1.6.0 '@vitest/snapshot': 1.6.0 '@vitest/spy': 1.6.0 - '@vitest/ui': 1.6.0(vitest@1.6.0) '@vitest/utils': 1.6.0 acorn-walk: 8.3.2 chai: 4.4.1 @@ -4889,6 +4924,8 @@ snapshots: vite: 5.2.11 vite-node: 1.6.0 why-is-node-running: 2.2.2 + optionalDependencies: + '@vitest/ui': 1.6.0(vitest@1.6.0) transitivePeerDependencies: - less - lightningcss @@ -4915,8 +4952,9 @@ snapshots: '@vue/compiler-dom': 3.4.27 '@vue/compiler-sfc': 3.4.27 '@vue/runtime-dom': 3.4.27 - '@vue/server-renderer': 3.4.27(vue@3.4.27) + '@vue/server-renderer': 3.4.27(vue@3.4.27(typescript@5.4.5)) '@vue/shared': 3.4.27 + optionalDependencies: typescript: 5.4.5 wcwidth@1.0.1: