### Example Version Vectors Source: https://loro.dev/docs/advanced/version_deep_dive Illustrates example Version Vectors A and B, showing operation counts for different peers. ```javascript const A = { 0: 2, 1: 3, }; ``` ```javascript const B = { 0: 5, 1: 3, 2: 9, }; ``` -------------------------------- ### Parallel Container Initialization and Overwrite Example Source: https://loro.dev/docs/advanced/cid Demonstrates a scenario where child containers are initialized in parallel, leading to potential overwrites and data loss if not handled carefully. This example highlights the risk associated with concurrent container creation. ```typescript const a: string = "hello"; const doc = new LoroDoc(); const map = doc.getMap("map"); // Parallel initialization of child containers const docB = doc.fork(); const textA = doc.getMap("map").setContainer("text", new LoroText()); textA.insert(0, "A"); const textB = docB.getMap("map").setContainer("text", new LoroText()); textB.insert(0, "B"); doc.import(docB.export({ mode: "update" })); // Result: Either { "meta": { "text": "A" } } or { "meta": { "text": "B" } } ``` -------------------------------- ### Undo/Redo with Cursor Restoration Example Source: https://loro.dev/docs/advanced/undo Demonstrates how to use the UndoManager to store and restore cursor positions during undo/redo operations. This example shows cursor transformation after text deletion and verifies cursor positions after an undo action. ```typescript import { LoroDoc, UndoManager, Cursor } from "loro-crdt"; import { expect } from "expect"; // ---cut--- const doc = new LoroDoc(); let cursors: Cursor[] = []; let poppedCursors: Cursor[] = []; const undo = new UndoManager(doc, { mergeInterval: 0, onPop: (isUndo, value, counterRange) => { poppedCursors = value.cursors; }, onPush: () => { return { value: null, cursors: cursors }; }, }); doc.getText("text").insert(0, "hello world"); doc.commit(); cursors = [ doc.getText("text").getCursor(0)ீர்கள்!, doc.getText("text").getCursor(5)ீர்கள்!, ]; // delete "hello ", the cursors should be transformed doc.getText("text").delete(0, 6); doc.commit(); expect(poppedCursors.length).toBe(0); undo.undo(); expect(poppedCursors.length).toBe(2); expect(doc.toJSON()).toStrictEqual({ text: "hello world", }); // expect the cursors to be transformed back expect(doc.getCursorPos(poppedCursors[0]).offset).toBe(0); expect(doc.getCursorPos(poppedCursors[1]).offset).toBe(5); ``` -------------------------------- ### Install loro-crdt with npm, pnpm, or yarn Source: https://loro.dev/docs/tutorial/get_started Choose your preferred package manager to install the loro-crdt NPM package. ```bash npm install loro-crdt # Or pnpm install loro-crdt # Or yarn add loro-crdt ``` -------------------------------- ### Get Version Vector Source: https://loro.dev/docs/tutorial/loro_doc Retrieve the current version vector of the document. Also shows how to get the oplog version vector. ```javascript const doc = new LoroDoc(); // Get current version vector const vv = doc.version(); // Get oplog version vector (latest known version) const oplogVv = doc.oplogVersion(); ``` -------------------------------- ### Using Map Container Source: https://loro.dev/docs/tutorial/loro_doc Illustrates setting and getting key-value pairs in a map, including nested containers. ```javascript const doc = new LoroDoc(); const map = doc.getMap("map"); map.set("name", "John"); map.set("age", 30); console.log(map.get("name")); // "John" // Nested containers const userText = map.setContainer("bio", new LoroText()); userText.insert(0, "Software Engineer"); ``` -------------------------------- ### Get or Create LoroTree Container Source: https://loro.dev/docs/api/js Use `getTree` to get or create a tree container. This is ideal for representing hierarchical data structures. Learn about hierarchical editing and moves in Tree. ```javascript import { LoroDoc } from "loro-crdt"; const doc = new LoroDoc(); const tree = doc.getTree("fileSystem"); const root = tree.createNode(); ``` -------------------------------- ### Get or Create Container Source: https://loro.dev/docs/api/js Gets an existing container or creates a new regular child container. Prefer `ensureMergeable*` methods for concurrently created shared children. ```javascript import { LoroDoc, LoroText } from "loro-crdt"; const doc = new LoroDoc(); const map = doc.getMap("map"); const text = map.getOrCreateContainer("description", new LoroText()); ``` -------------------------------- ### Get or Create LoroMap Container Source: https://loro.dev/docs/api/js Use `getMap` to get or create a map container. This is suitable for key-value data structures. Refer to Map for basics and patterns. ```javascript import { LoroDoc } from "loro-crdt"; const doc = new LoroDoc(); const map = doc.getMap("settings"); map.set("theme", "dark"); ``` -------------------------------- ### Get or Create LoroText Container Source: https://loro.dev/docs/api/js Use `getText` to get or create a text container. This is suitable for collaborative text editing. See Text and Marks for more details. ```javascript import { LoroDoc } from "loro-crdt"; const doc = new LoroDoc(); const text = doc.getText("content"); text.insert(0, "Hello"); ``` -------------------------------- ### Get Root Nodes of LoroTree Source: https://loro.dev/docs/api/js Retrieves all root nodes from a LoroTree. This is useful for starting traversal or understanding the top-level structure of the tree. ```javascript import { LoroDoc } from "loro-crdt"; const doc = new LoroDoc(); const tree = doc.getTree("tree"); const rootNodes = tree.roots(); ``` -------------------------------- ### Prepare Sample Data for JSONPath Queries Source: https://loro.dev/docs/advanced/jsonpath This snippet sets up a Loro document with sample bookstore data using JavaScript objects. It demonstrates how to initialize a LoroDoc, populate a map with test data, and commit the changes. Prefer explicit LoroMap and LoroList composition in production. ```javascript import { LoroDoc } from "loro-crdt"; const doc = new LoroDoc(); const testData = { books: [ { title: "1984", author: "George Orwell", price: 10, available: true, isbn: "978-0451524935" }, { title: "Animal Farm", author: "George Orwell", price: 8, available: true }, { title: "Brave New World", author: "Aldous Huxley", price: 12, available: false }, { title: "Fahrenheit 451", author: "Ray Bradbury", price: 9, available: true, isbn: "978-1451673318" }, { title: "The Great Gatsby", author: "F. Scott Fitzgerald", price: null, available: true }, { title: "To Kill a Mockingbird", author: "Harper Lee", price: 11, available: true }, { title: "The Catcher in the Rye", author: "J.D. Salinger", price: 10, available: false }, { title: "Lord of the Flies", author: "William Golding", price: 9, available: true }, { title: "Pride and Prejudice", author: "Jane Austen", price: 7, available: true }, { title: "The Hobbit", author: "J.R.R. Tolkien", price: 14, available: true } ], featured_author: "George Orwell", min_price: 10, featured_authors: ["George Orwell", "Jane Austen"], }; const store = doc.getMap("store"); Object.entries(testData).forEach(([key, value]) => store.set(key, value)); doc.commit(); ``` -------------------------------- ### Get or Create LoroList Container Source: https://loro.dev/docs/api/js Use `getList` to get or create a list container. This is suitable for ordered collections where elements might be added or removed. Consult List and Movable List and the type selection guide Choosing CRDT Types for guidance. ```javascript import { LoroDoc } from "loro-crdt"; const doc = new LoroDoc(); const list = doc.getList("items"); list.push("Item 1"); ``` -------------------------------- ### Minimal Browser Example using ESM Imports Source: https://loro.dev/docs/tutorial/get_started This HTML snippet demonstrates how to use Loro directly in the browser via ESM imports from a CDN. ```html ESM Module Example
``` -------------------------------- ### Get Loro Version Source: https://loro.dev/docs/api/js Retrieves the current version string of the Loro CRDT library. Use this to check the installed version or for compatibility checks. ```javascript import { LORO_VERSION } from "loro-crdt"; const version = LORO_VERSION(); console.log("Loro version:", version); ``` -------------------------------- ### Counter System Example Source: https://loro.dev/docs/concepts/peerid_management Demonstrates how the monotonic counter works per peer. Each operation increments the counter for the assigned Peer ID. ```javascript const doc = new LoroDoc(); doc.setPeerId("1"); const text = doc.getText("text"); text.insert(0, "H"); // Operation ("1", 0) text.insert(1, "i!"); // Operation ("1", 1) and Operation ("1", 2) are created console.log(doc.version()); // { "1": 2 } ``` -------------------------------- ### Track Cursor Position Across Edits Source: https://loro.dev/docs/tutorial/loro_doc Demonstrates how to get and track cursor positions in a Loro document's text. Ensure the cursor is obtained after initial text setup. ```typescript import { LoroDoc } from "loro-crdt"; // ---cut--- const doc = new LoroDoc(); const text = doc.getText("text"); text.insert(0, "123"); // Get cursor at position with side (-1, 0, or 1) const cursor = text.getCursor(0, 0); if (cursor) { // Get current cursor position const pos = doc.getCursorPos(cursor); console.log(pos.offset); // Current position console.log(pos.side); // Cursor side // Cursor position updates automatically with concurrent edits text.insert(0, "abc"); const newPos = doc.getCursorPos(cursor); console.log(newPos.offset); // Position updated } ``` -------------------------------- ### Workflow Example: Squash-like Diffs Source: https://loro.dev/docs/api/js Demonstrates using diff and applyDiff to send a compact change set between a base version and a new version, compressing out canceling operations. ```javascript import { LoroDoc } from "loro-crdt"; const baseDoc = new LoroDoc(); const baseText = baseDoc.getText("text"); baseText.insert(0, "hello world"); // Fork to make isolated edits const newDoc = baseDoc.fork(); const newText = newDoc.getText("text"); newText.insert(0, "abc"); newText.delete(0, 4); const diff = newDoc.diff(baseDoc.frontiers(), newDoc.frontiers()); console.log(diff); // [ // [ // "cid:root-text:Text", // { type: "text", diff: [ { delete: 1 } ] } // ] // ] baseDoc.applyDiff(diff); console.log(baseDoc.toJSON()); // { text: "ello world" } ``` -------------------------------- ### get Source: https://loro.dev/docs/api/js Gets the value for a key from the map. Returns undefined if the key does not exist. ```APIDOC ## get(key: string): Value | Container | undefined ### Description Gets the value for a key. ### Parameters #### Path Parameters * **key** (string) - Required - The key ### Returns The value or undefined ### Example ```javascript import { LoroDoc } from "loro-crdt"; const doc = new LoroDoc(); const map = doc.getMap("map"); const name = map.get("name"); ``` ``` -------------------------------- ### Defining Text Selection Ranges Source: https://loro.dev/docs/concepts/cursor_stable_positions Shows how to define the start and end cursors for a text selection range. ```javascript const doc = new LoroDoc(); const text = doc.getText("text"); text.insert(0, "Hello World"); // Selection range const start = text.getCursor(0, -1); // Anchor const end = text.getCursor(5, 1); // Head ``` -------------------------------- ### Practical Example: Saving and Restoring Checkpoints Source: https://loro.dev/docs/concepts/frontiers Illustrates saving document states using frontiers as checkpoints and restoring to these saved states with LoroDoc. ```typescript import { LoroDoc } from "loro-crdt"; const doc = new LoroDoc(); const text = doc.getText("content"); const checkpoints = new Map(); // Save checkpoint with frontiers text.insert(0, "Draft version"); checkpoints.set("draft", doc.frontiers()); // Make changes text.delete(0, 5); text.insert(0, "Final"); checkpoints.set("final", doc.frontiers()); // Restore to any checkpoint doc.checkout(checkpoints.get("draft")); console.log(text.toString()); // "Draft version" ``` -------------------------------- ### Using Tree Container Source: https://loro.dev/docs/tutorial/loro_doc Demonstrates creating a tree structure with nodes and setting data for each node. ```javascript const doc = new LoroDoc(); const tree = doc.getTree("tree"); const root = tree.createNode(); root.data.set("name", "Root"); const child1 = root.createNode(); child1.data.set("name", "Child 1"); const child2 = root.createNode(); child2.data.set("name", "Child 2"); ``` -------------------------------- ### Basic Document Operations and Versioning Source: https://loro.dev/docs/concepts/oplog_docstate Demonstrates basic text insertion and how to check the OpLog version versus the current document state version. Assumes the document is attached, meaning the state and log versions are synchronized. ```typescript const doc = new LoroDoc(); // Edit updates both doc.getText("text").insert(0, "Hello"); console.log(doc.oplogVersion()); // Latest known version console.log(doc.version()); // The version of the current state of the document // If the document is attached, they are the same. ``` -------------------------------- ### Get All Ephemeral States Source: https://loro.dev/docs/api/js Retrieves all currently stored ephemeral states as a partial object. This is useful for getting a snapshot of all transient data. ```typescript import { EphemeralStore } from "loro-crdt"; const store = new EphemeralStore(30000); store.set("cursor", { line: 10 }); store.set("user", { name: "Alice" }); // Usage example: const allStates = store.getAllStates(); console.log(allStates); ``` -------------------------------- ### Using List Container Source: https://loro.dev/docs/tutorial/loro_doc Shows how to insert items into a list and add nested containers like text. ```javascript const doc = new LoroDoc(); const list = doc.getList("list"); list.insert(0, "first"); list.insert(1, "second"); console.log(list.toArray()); // ["first", "second"] // Nested containers const nestedText = list.insertContainer(2, new LoroText()); nestedText.insert(0, "nested text"); ``` -------------------------------- ### Get Frontiers Source: https://loro.dev/docs/tutorial/loro_doc Obtain the current frontiers of the document, which represent the latest operations from each peer. Also shows how to get oplog frontiers. ```javascript const doc = new LoroDoc(); doc.setPeerId("0"); doc.getMap("map").set("text", "Hello"); // Get current frontiers const frontiers = doc.frontiers(); // Get oplog frontiers (latest known version) const oplogFrontiers = doc.oplogFrontiers(); // { "0": 0 } ``` -------------------------------- ### Using Text Container Source: https://loro.dev/docs/tutorial/loro_doc Demonstrates inserting text and applying rich text formatting like bold and links. ```javascript const doc = new LoroDoc(); const text = doc.getText("text"); text.insert(0, "Hello"); text.insert(5, " World!"); console.log(text.toString()); // "Hello World!" // Rich text support doc.configTextStyle({ bold: { expand: "after" }, link: { expand: "none" }, }); text.mark({ start: 0, end: 5 }, "bold", true); ``` -------------------------------- ### EphemeralStore Synchronization Example Source: https://loro.dev/docs/api/js This snippet shows how to initialize two EphemeralStore instances, subscribe to local updates from one store and apply them to the other, and subscribe to all updates on the second store. It also demonstrates setting a value, encoding it, and applying the encoded data. ```typescript import { EphemeralStore } from "loro-crdt"; // Assume we have: declare const websocket: { send: (data: Uint8Array) => void; on: (event: string, handler: (data: any) => void) => void; }; const store = new EphemeralStore(30000); const store2 = new EphemeralStore(30000); // Subscribe to local updates store.subscribeLocalUpdates((data) => { store2.apply(data); }); // Subscribe to all updates store2.subscribe((event) => { console.log("event:", event); }); // Set a value store.set("key", "value"); // Encode the value const encoded = store.encode("key"); // Apply the encoded value store2.apply(encoded); ``` -------------------------------- ### LoroList Methods Source: https://loro.dev/docs/api/js Provides documentation for various methods of the LoroList CRDT, including getting a cursor, converting to an array, clearing the list, accessing its length, checking its kind, converting to JSON, retrieving the parent container, checking attachment status, getting the attached version, checking deletion status, and getting shallow values. ```APIDOC ## getCursor(index: number) ### Description Retrieves a cursor object at the specified index in the list. ### Parameters #### Path Parameters - **index** (number) - Required - The index at which to get the cursor. ### Returns Cursor object or undefined ### Example ```javascript import { LoroDoc } from "loro-crdt"; const doc = new LoroDoc(); const list = doc.getList("list"); list.push("a", "b", "c"); const cursor = list.getCursor(2); ``` ``` ```APIDOC ## toArray(): (Value | Container)[] ### Description Converts the list to a JavaScript array. ### Returns Array of values ### Example ```javascript import { LoroDoc } from "loro-crdt"; const doc = new LoroDoc(); const list = doc.getList("list"); list.push("a", "b", "c"); const array = list.toArray(); ``` ``` ```APIDOC ## clear(): void ### Description Removes all elements from the list. ### Example ```javascript import { LoroDoc } from "loro-crdt"; const doc = new LoroDoc(); const list = doc.getList("list"); list.push("a", "b", "c"); list.clear(); ``` ``` ```APIDOC ## length: number ### Description Gets the number of elements in the list. ### Returns List length ### Example ```javascript import { LoroDoc } from "loro-crdt"; const doc = new LoroDoc(); const list = doc.getList("list"); list.push("a"); list.push("b"); list.push("c"); console.log(`List has ${list.length} items`); ``` ``` ```APIDOC ## kind(): "List" ### Description Returns the container type. ### Returns “List” ### Example ```javascript import { LoroDoc } from "loro-crdt"; const doc = new LoroDoc(); const list = doc.getList("list"); const type = list.kind(); // "List" ``` ``` ```APIDOC ## toJSON(): any ### Description Converts the list to JSON representation. ### Returns JSON array ### Example ```javascript import { LoroDoc } from "loro-crdt"; const doc = new LoroDoc(); const list = doc.getList("list"); list.push(1, 2, 3); // Usage example: const json = list.toJSON(); // [1, 2, 3] ``` ``` ```APIDOC ## parent(): Container | undefined ### Description Gets the parent container if this list is nested. ### Returns Parent container or undefined ### Example ```javascript import { LoroDoc } from "loro-crdt"; const doc = new LoroDoc(); const map = doc.getMap("map"); const list = map.setContainer("nested", doc.getList("list")); // Usage example: const parent = list.parent(); // Returns the map ``` ``` ```APIDOC ## isAttached(): boolean ### Description Checks if the container is attached to a document. ### Returns True if attached ### Example ```javascript import { LoroDoc, LoroList } from "loro-crdt"; const doc = new LoroDoc(); const list = new LoroList(); const attached = list.isAttached(); // false until attached to doc ``` ``` ```APIDOC ## getAttached(): LoroList | undefined ### Description Gets the attached version of this container. ### Returns Attached container or undefined ### Example ```javascript import { LoroDoc, LoroList } from "loro-crdt"; const doc = new LoroDoc(); const list = new LoroList(); const attached = list.getAttached(); ``` ``` ```APIDOC ## isDeleted(): boolean ### Description Checks if the container has been deleted. ### Returns True if deleted ### Example ```javascript import { LoroDoc } from "loro-crdt"; const doc = new LoroDoc(); const list = doc.getList("list"); const deleted = list.isDeleted(); ``` ``` ```APIDOC ## getShallowValue(): Value[] ### Description Gets the list values with sub-containers as IDs. ### Returns Array of values ### Example ```javascript import { LoroDoc } from "loro-crdt"; const doc = new LoroDoc(); const list = doc.getList("list"); list.push(1, 2); // Usage example: const values = list.getShallowValue(); // [1, 2] ``` ``` ```APIDOC ## readonly id: ContainerID ### Description Gets the unique container ID. ### Example ```javascript import { LoroDoc } from "loro-crdt"; const doc = new LoroDoc(); const list = doc.getList("list"); const containerId = list.id; ``` ``` -------------------------------- ### Using the Counter in LoroDoc Source: https://loro.dev/docs/tutorial/counter Demonstrates how to initialize a Counter, apply changes, and check its final value. Ensure LoroDoc is imported and initialized before use. ```javascript const doc = new LoroDoc(); const counter = doc.getCounter("counter"); counter.increment(1); counter.increment(2); counter.decrement(1); expect(counter.value).toBe(2); ``` -------------------------------- ### Get or Create LoroCounter Container Source: https://loro.dev/docs/api/js Use `getCounter` to get or create a counter container. Counters are specialized CRDTs for summing concurrent increments. See Counter for more information. ```javascript import { LoroDoc } from "loro-crdt"; const doc = new LoroDoc(); const counter = doc.getCounter("likes"); counter.increment(1); ``` -------------------------------- ### Shallow Snapshots Source: https://loro.dev/docs/api/js Demonstrates creating and importing shallow snapshots. This mode is efficient for storage as it strips history, suitable for state synchronization where history is not needed. ```javascript import { LoroDoc } from "loro-crdt"; const doc = new LoroDoc(); // Create shallow snapshot const frontiers = doc.frontiers(); const shallowSnapshot = doc.export({ mode: "shallow-snapshot", frontiers: frontiers, }); // Import shallow snapshot const newDoc = new LoroDoc(); newDoc.import(shallowSnapshot); ``` -------------------------------- ### Initialize UndoManager with Options Source: https://loro.dev/docs/advanced/undo Instantiate an UndoManager, configuring options like maximum undo steps, merge interval, excluded operation prefixes, and callback functions for push and pop events. ```javascript const undoManager = new UndoManager(doc, { maxUndoSteps: 100, // default 100 mergeInterval: 1000, // default 1000ms excludeOriginPrefixes: ["sys:"], // default [] onPush: (isUndo, range, event) => { return { value: null, cursors: [] }; }, onPop: (isUndo, value, counterRange) => { return; }, }); ``` -------------------------------- ### slice(start: number, end: number): string Source: https://loro.dev/docs/api/js Extracts a section of the text using UTF-16 code unit positions. It takes a start and end index and returns the corresponding substring. ```APIDOC ## slice(start: number, end: number): string ### Description Extracts a section of the text using UTF-16 code unit positions. ### Parameters #### Path Parameters - **start** (number) - Required - Start UTF-16 code unit index - **end** (number) - Required - End UTF-16 code unit index (exclusive) ### Returns Sliced text (string) ### Request Example ```javascript import { LoroDoc } from "loro-crdt"; const doc = new LoroDoc(); const text = doc.getText("text"); text.insert(0, "Hello 😀 World"); const slice1 = text.slice(0, 5); // "Hello" const slice2 = text.slice(6, 8); // "😀" (emoji spans 6-8) const slice3 = text.slice(9, 14); // "World" ``` ``` -------------------------------- ### nodes Source: https://loro.dev/docs/api/js Gets all nodes in the LoroTree. ```APIDOC ## nodes ### Description Gets all nodes in the tree. ### Returns Array of all nodes ### Example ```javascript import { LoroDoc } from "loro-crdt"; const doc = new LoroDoc(); const tree = doc.getTree("tree"); const allNodes = tree.nodes(); ``` ``` -------------------------------- ### Comparing Batch Import vs. Individual Import Source: https://loro.dev/docs/advanced/import_batch Demonstrates the difference in performance between importing multiple updates using `importBatch` and importing them individually in a loop. Use `importBatch` for significantly faster updates. ```javascript const doc = new LoroDoc(); doc.getText("text").update("Hello"); const update1 = doc.export({ mode: "update" }); const version = doc.version(); doc.getText("text").update("Hello World"); const update2 = doc.export({ mode: "update", from: version }); const newDoc1 = new LoroDoc(); newDoc1.importBatch([update1, update2]); // faster const newDoc2 = new LoroDoc(); for (const update of [update1, update2]) { // slower newDoc2.import(update); } ``` -------------------------------- ### Basic Document Operations Source: https://loro.dev/docs/advanced/doc_state_and_oplog Demonstrates basic document creation and editing. Use this to understand how edits update both the OpLog and the current document state. `oplogVersion()` returns the latest known version, while `version()` returns the version of the current state. ```typescript const doc = new LoroDoc(); // Edit updates both doc.getText("text").insert(0, "Hello"); console.log(doc.oplogVersion()); // Latest known version console.log(doc.version()); // The version of the current state of the document // If the document is attached, they are the same. ``` -------------------------------- ### Get or Create LoroMovableList Container Source: https://loro.dev/docs/api/js Use `getMovableList` to get or create a movable list container. This type is optimized for scenarios involving concurrent reordering of elements. See List and Movable List and Choosing CRDT Types. ```javascript import { LoroDoc } from "loro-crdt"; const doc = new LoroDoc(); const movableList = doc.getMovableList("tasks"); movableList.push("Task 1"); movableList.push("Task 2"); movableList.push("Task 3"); movableList.move(0, 2); // Move first item to third position ``` -------------------------------- ### Create and Set Node Data Source: https://loro.dev/docs/api/js Demonstrates how to create a new tree node and set its metadata using a LoroMap. This is useful for storing custom information associated with each node. ```javascript import { LoroDoc } from "loro-crdt"; const doc = new LoroDoc(); const tree = doc.getTree("tree"); const node = tree.createNode(); node.data.set("title", "Node Title"); node.data.set("expanded", true); ``` -------------------------------- ### Example: Successful Import Operations Source: https://loro.dev/docs/tutorial/sync Logs the 'success' field of the import result to show which operation ranges from each peer were applied. ```javascript // Assuming importResult is the return value of doc.import(bytes) console.log(importResult.success); // Example output: // { // "clientA_peerId": { "start": 0, "end": 50 }, // "server_peerId": { "start": 120, "end": 150 } // } // This means operations from clientA (counters 0-49) and // operations from server (counters 120-149) were successfully imported. ``` -------------------------------- ### roots Source: https://loro.dev/docs/api/js Gets all root nodes in the LoroTree. ```APIDOC ## roots ### Description Gets all root nodes in the tree. ### Returns Array of root nodes ### Example ```javascript import { LoroDoc } from "loro-crdt"; const doc = new LoroDoc(); const tree = doc.getTree("tree"); const rootNodes = tree.roots(); ``` ``` -------------------------------- ### Basic Synchronization Source: https://loro.dev/docs/api/js Demonstrates exporting updates from one document and importing them into another. This is useful for one-time sync operations between peers. ```javascript import { LoroDoc } from "loro-crdt"; // Peer A: Export updates const doc1 = new LoroDoc(); doc1.getText("text").insert(0, "Hello"); const updates = doc1.export({ mode: "update" }); // Peer B: Import updates const doc2 = new LoroDoc(); doc2.import(updates); // now doc2.getText("text").toString() === "Hello" ``` -------------------------------- ### Example: Pending Import Operations Due to Dependencies Source: https://loro.dev/docs/tutorial/sync Checks if the 'pending' field exists and logs it, indicating operation ranges that are waiting for prerequisite updates. ```javascript // Assuming importResult is the return value of doc.import(bytes) if (importResult.pending) { console.log(importResult.pending); // Example output: // { // "clientA_peerId": { "start": 50, "end": 60 }, // "clientB_peerId": { "start": 10, "end": 25 } // } // This means operations from clientA (counters 50-59) and // operations from clientB (counters 10-24) are pending due to missing dependencies. ``` -------------------------------- ### id Source: https://loro.dev/docs/api/js Gets the unique container ID. ```APIDOC ## id ### Description Gets the unique container ID. ### Example ```javascript import { LoroDoc } from "loro-crdt"; const doc = new LoroDoc(); const map = doc.getMap("map"); const containerId = map.id; ``` ``` -------------------------------- ### getAttached Source: https://loro.dev/docs/api/js Gets the attached version of this container. ```APIDOC ## getAttached ### Description Gets the attached version of this container. ### Returns Attached container or undefined ### Example ```javascript import { LoroDoc, LoroMap } from "loro-crdt"; const doc = new LoroDoc(); const map = new LoroMap(); const attached = map.getAttached(); ``` ``` -------------------------------- ### Basic LoroDoc Usage Source: https://loro.dev/docs/api/js Demonstrates basic LoroDoc initialization, text manipulation, subscribing to changes, and exporting updates for synchronization. ```typescript import { LoroDoc } from "loro-crdt"; const doc = new LoroDoc(); const text = doc.getText("text"); text.insert(0, "Hello World"); // Subscribe to changes const unsubscribe = doc.subscribe((event) => { console.log("Document changed:", event); }); // Export updates for synchronization const updates = doc.export({ mode: "update" }); ``` -------------------------------- ### values Source: https://loro.dev/docs/api/js Gets all values present in the map. ```APIDOC ## values(): (Value | Container)[] ### Description Gets all values in the map. ### Returns Array of values ### Example ```javascript import { LoroDoc } from "loro-crdt"; const doc = new LoroDoc(); const map = doc.getMap("map"); const allValues = map.values(); ``` ``` -------------------------------- ### Loro API Usage with Eg-Walker Inspired Optimizations Source: https://loro.dev/docs/advanced/event_graph_walker Demonstrates the simple, index-based API for text manipulation in Loro, leveraging Eg-Walker-inspired efficiency for operations and merging. ```javascript // Simple API with powerful internals const doc = new Loro(); const text = doc.getText("content"); // Just use indices - Eg-Walker handles the complexity text.insert(5, "Hello"); text.delete(2, 3); // Efficient merging happens automatically doc.import(remoteUpdate); ``` -------------------------------- ### keys Source: https://loro.dev/docs/api/js Gets all keys present in the map. ```APIDOC ## keys(): string[] ### Description Gets all keys in the map. ### Returns Array of keys ### Example ```javascript import { LoroDoc } from "loro-crdt"; const doc = new LoroDoc(); const map = doc.getMap("map"); const allKeys = map.keys(); ``` ``` -------------------------------- ### groupStart() Source: https://loro.dev/docs/api/js Begins a manual grouping of subsequent operations, allowing them to be undone as a single unit. ```APIDOC ## groupStart(): void ### Description Begin a manual grouping of subsequent commits into a single undo step. ### Behavior * Wrap consecutive `doc.commit()` calls so they undo together * Calling `groupStart` again before `groupEnd` throws and leaves the current group unchanged * Conflicting remote imports may automatically end the group and split the undo item ### Example ```javascript import { LoroDoc, UndoManager } from "loro-crdt"; const doc = new LoroDoc(); const undo = new UndoManager(doc, {}); const text = doc.getText("text"); undo.groupStart(); text.update("hello", undefined); doc.commit(); text.update("hello world", undefined); doc.commit(); undo.groupEnd(); undo.undo(); console.log(text.toString()); // "" ``` ``` -------------------------------- ### Basic List Usage with Concurrent Updates Source: https://loro.dev/docs/tutorial/list Demonstrates basic List operations like push, delete, and insert. Shows how concurrent updates to the same index are handled and merged. ```typescript const docA = new LoroDoc(); docA.setPeerId("1"); const listA = docA.getList("list"); listA.push(0); listA.push(1); listA.push(2); const bytes: Uint8Array = docA.export({ mode: "snapshot" }); const docB = Loro.fromSnapshot(bytes); docB.setPeerId("2"); const listB = docB.getList("list"); { // Concurrently docA and docB update element at index 2 // docA updates it to 8 // docB updates it to 9 // docA.toJSON() should return { list: [0, 1, 8] } // docB.toJSON() should return { list: [0, 1, 9] } listB.delete(2, 1); listB.insert(2, 9); expect(docB.toJSON()).toStrictEqual({ list: [0, 1, 9] }); listA.delete(2, 1); listA.insert(2, 8); expect(docA.toJSON()).toStrictEqual({ list: [0, 1, 8] }); } { // Merge docA and docB docA.import(docB.export({ mode: "update", from: docA.version() })); docB.import(docA.export({ mode: "update", from: docB.version() })); } expect(docA.toJSON()).toStrictEqual({ list: [0, 1, 8, 9] }); expect(docB.toJSON()).toStrictEqual({ list: [0, 1, 8, 9] }); ``` -------------------------------- ### Get Text Length with UTF-16 Consideration Source: https://loro.dev/docs/api/js Gets the length of the text in UTF-16 code units. Note that characters outside the Basic Multilingual Plane, like complex emojis, count as 2 units, affecting index-based operations. ```javascript import { LoroDoc } from "loro-crdt"; const doc = new LoroDoc(); const text = doc.getText("text"); text.insert(0, "Hello"); console.log(text.length); // 5 text.insert(5, " 😀"); console.log(text.length); // 8 (space + emoji which counts as 2) ``` -------------------------------- ### getNodeByID Source: https://loro.dev/docs/api/js Gets a node handler by its ID from the LoroTree. ```APIDOC ## getNodeByID ### Description Gets a node handler by its ID. ### Parameters * `id` - Node ID ### Returns Node handler or undefined ### Example ```javascript import { LoroDoc, TreeID } from "loro-crdt"; const doc = new LoroDoc(); const tree = doc.getTree("tree"); const _node = tree.createNode(); const nodeId = _node.id; // Usage example: const node = tree.getNodeByID(nodeId); if (node) { node.data.set("label", "New Label"); } ``` ``` -------------------------------- ### Create EphemeralStore Instance Source: https://loro.dev/docs/api/js Initializes a new EphemeralStore. Set a timeout in milliseconds to define how long peer states are considered valid. Defaults to 30 seconds. ```typescript import { EphemeralStore } from "loro-crdt"; // Create ephemeral store with 30 second timeout const store = new EphemeralStore(30000); ``` -------------------------------- ### Basic Container Operations (List and Map) Source: https://loro.dev/docs/tutorial/get_started Demonstrates basic operations on List and Map containers, including insertion, deletion, and setting values. Shows how to insert and set container types within other containers. ```typescript const doc = new LoroDoc(); const list: LoroList = doc.getList("list"); list.insert(0, "A"); list.insert(1, "B"); list.insert(2, "C"); const map: LoroMap = doc.getMap("map"); // map can only has string key map.set("key", "value"); expect(doc.toJSON()).toStrictEqual({ list: ["A", "B", "C"], map: { key: "value" }, }); // delete 2 element at index 0 list.delete(0, 2); expect(doc.toJSON()).toStrictEqual({ list: ["C"], map: { key: "value" }, }); // Insert a text container to the list const text = list.insertContainer(0, new LoroText()); text.insert(0, "Hello"); text.insert(0, "Hi! "); expect(doc.toJSON()).toStrictEqual({ list: ["Hi! Hello", "C"], map: { key: "value" }, }); // Insert a list container to the map const list2 = map.setContainer("test", new LoroList()); list2.insert(0, 1); expect(doc.toJSON()).toStrictEqual({ list: ["Hi! Hello", "C"], map: { key: "value", test: [1] }, }); ``` -------------------------------- ### getShallowValue Source: https://loro.dev/docs/api/js Gets the map values with sub-containers as IDs. ```APIDOC ## getShallowValue ### Description Gets the map values with sub-containers as IDs. ### Returns Object with values ### Example ```javascript import { LoroDoc } from "loro-crdt"; const doc = new LoroDoc(); const map = doc.getMap("map"); map.set("key", "value"); // Usage example: const values = map.getShallowValue(); // { key: "value" } ``` ``` -------------------------------- ### parent Source: https://loro.dev/docs/api/js Gets the parent container if the map is nested. ```APIDOC ## parent ### Description Gets the parent container if this map is nested. ### Returns Parent container or undefined ### Example ```javascript import { LoroDoc } from "loro-crdt"; const doc = new LoroDoc(); const list = doc.getList("list"); const map = list.insertContainer(0, doc.getMap("nested")); // Usage example: const parent = map.parent(); // Returns the list ``` ``` -------------------------------- ### Basic LoroDoc Operations and Commit Source: https://loro.dev/docs/concepts/operations_changes Demonstrates basic text insertion operations and how they are grouped into a single change upon committing. ```javascript const doc = new LoroDoc(); const text = doc.getText("text"); text.insert(0, "Hello"); // Operation text.insert(5, " World"); // Operation doc.commit(); // Groups into one Change ``` -------------------------------- ### Real-time Sync with Offline Changes Source: https://loro.dev/docs/tutorial/sync Illustrates how two peers can synchronize when one has made offline changes. It covers exchanging version information, requesting missing updates, and establishing real-time sync subscriptions. ```typescript const doc1 = new LoroDoc(); doc1.getText("text").insert(0, "Hello"); // Peer2 joins the network const doc2 = new LoroDoc(); // ... doc2 may import its local snapshot // 1. Exchange version information const peer2Version = doc2.oplogVersion(); const peer1Version = doc1.oplogVersion(); // 2. Request missing updates from existing peers const missingOps = doc1.export({ mode: "update", from: peer2Version, }); doc2.import(missingOps); const missingOps2 = doc2.export({ mode: "update", from: peer1Version, }); doc1.import(missingOps2); // 3. Establish realtime sync doc2.subscribeLocalUpdates((update) => { // websocket.send(update); }); doc1.subscribeLocalUpdates((update) => { // websocket.send(update); }); // Now both peers are in sync and can collaborate ``` -------------------------------- ### size Source: https://loro.dev/docs/api/js Gets the number of key-value pairs in the map. ```APIDOC ## size ### Description Gets the number of key-value pairs. ### Returns Map size ### Example ```javascript import { LoroDoc } from "loro-crdt"; const doc = new LoroDoc(); const map = doc.getMap("map"); console.log(`Map has ${map.size} entries`); ``` ``` -------------------------------- ### Using MovableList Container Source: https://loro.dev/docs/tutorial/loro_doc Shows how to insert items into a movable list and change their order. ```javascript const doc = new LoroDoc(); const movableList = doc.getMovableList("tasks"); movableList.insert(0, "Task 1"); movableList.insert(1, "Task 2"); movableList.move(0, 1); // Move Task 1 after Task 2 ``` -------------------------------- ### entries Source: https://loro.dev/docs/api/js Gets all key-value pairs present in the map. ```APIDOC ## entries(): [string, Value | Container][] ### Description Gets all key-value pairs. ### Returns Array of entries ### Example ```javascript import { LoroDoc } from "loro-crdt"; const doc = new LoroDoc(); const map = doc.getMap("map"); for (const [key, value] of map.entries()) { console.log(`${key}: ${value}`); } ``` ``` -------------------------------- ### Basic Usage of Loro Frontiers Source: https://loro.dev/docs/concepts/frontiers Demonstrates how to get current frontiers, use them for checkpoints, and restore a document to a previous state using LoroDoc. ```typescript import { LoroDoc } from "loro-crdt"; const doc = new LoroDoc(); const text = doc.getText("content"); text.insert(0, "Hello World"); // Get current frontiers (usually 1-2 elements) const frontiers = doc.frontiers(); console.log(frontiers); // [{ peer: "...", counter: 0 }] // Use frontiers for checkpoints const checkpoint = doc.frontiers(); text.insert(5, " Beautiful"); // Restore to checkpoint doc.checkout(checkpoint); console.log(text.toString()); // Back to "Hello World" ``` -------------------------------- ### Text.id Source: https://loro.dev/docs/api/js Gets the unique identifier for the LoroText container. ```APIDOC ## Text.id ### Description Gets the unique container ID. ### Example ```javascript import { LoroDoc } from "loro-crdt"; const doc = new LoroDoc(); const text = doc.getText("text"); const containerId = text.id; ``` ``` -------------------------------- ### Ephemeral Store Basic Usage Source: https://loro.dev/docs/tutorial/ephemeral Demonstrates setting, getting, encoding, and subscribing to changes in the Ephemeral Store. Ensure you handle subscription objects to prevent garbage collection. ```typescript import { EphemeralStore, EphemeralStoreEvent } from "loro-crdt"; import { expect } from "expect"; const store = new EphemeralStore(); // Set ephemeral data store.set("loro-prosemirror", { anchor: { pos: 0 }, focus: { pos: 5 }, user: "Alice", }); store.set("online-users", ["Alice", "Bob"]); expect(store.get("online-users")).toEqual(["Alice", "Bob"]); // Encode only the data for `loro-prosemirror` const encoded = store.encode("loro-prosemirror"); store.subscribe((e: EphemeralStoreEvent) => { // Listen to changes from `local`, `remote`, or `timeout` events }); ``` -------------------------------- ### LoroCounter Value Source: https://loro.dev/docs/api/js Gets the current numeric value of the counter. ```APIDOC ## value: number ### Description Gets the current numeric value of the counter. ### Method value ### Returns Current numeric value ### Request Example ```javascript import { LoroDoc } from "loro-crdt"; const doc = new LoroDoc(); const counter = doc.getCounter("counter"); console.log(`Counter value: ${counter.value}`); ``` ```