UNPKG

loro-crdt

Version:

Loro CRDTs is a high-performance CRDT framework that makes your app state synchronized, collaborative and maintainable effortlessly.

1,501 lines (1,430 loc) 258 kB
let wasm; const heap = new Array(128).fill(undefined); heap.push(undefined, null, true, false); function getObject(idx) { return heap[idx]; } let WASM_VECTOR_LEN = 0; let cachedUint8ArrayMemory0 = null; function getUint8ArrayMemory0() { if (cachedUint8ArrayMemory0 === null || cachedUint8ArrayMemory0.byteLength === 0) { cachedUint8ArrayMemory0 = new Uint8Array(wasm.memory.buffer); } return cachedUint8ArrayMemory0; } const cachedTextEncoder = (typeof TextEncoder !== 'undefined' ? new TextEncoder('utf-8') : { encode: () => { throw Error('TextEncoder not available') } } ); const encodeString = (typeof cachedTextEncoder.encodeInto === 'function' ? function (arg, view) { return cachedTextEncoder.encodeInto(arg, view); } : function (arg, view) { const buf = cachedTextEncoder.encode(arg); view.set(buf); return { read: arg.length, written: buf.length }; }); function passStringToWasm0(arg, malloc, realloc) { if (realloc === undefined) { const buf = cachedTextEncoder.encode(arg); const ptr = malloc(buf.length, 1) >>> 0; getUint8ArrayMemory0().subarray(ptr, ptr + buf.length).set(buf); WASM_VECTOR_LEN = buf.length; return ptr; } let len = arg.length; let ptr = malloc(len, 1) >>> 0; const mem = getUint8ArrayMemory0(); let offset = 0; for (; offset < len; offset++) { const code = arg.charCodeAt(offset); if (code > 0x7F) break; mem[ptr + offset] = code; } if (offset !== len) { if (offset !== 0) { arg = arg.slice(offset); } ptr = realloc(ptr, len, len = offset + arg.length * 3, 1) >>> 0; const view = getUint8ArrayMemory0().subarray(ptr + offset, ptr + len); const ret = encodeString(arg, view); offset += ret.written; ptr = realloc(ptr, len, offset, 1) >>> 0; } WASM_VECTOR_LEN = offset; return ptr; } let cachedDataViewMemory0 = null; function getDataViewMemory0() { if (cachedDataViewMemory0 === null || cachedDataViewMemory0.buffer.detached === true || (cachedDataViewMemory0.buffer.detached === undefined && cachedDataViewMemory0.buffer !== wasm.memory.buffer)) { cachedDataViewMemory0 = new DataView(wasm.memory.buffer); } return cachedDataViewMemory0; } let heap_next = heap.length; function addHeapObject(obj) { if (heap_next === heap.length) heap.push(heap.length + 1); const idx = heap_next; heap_next = heap[idx]; heap[idx] = obj; return idx; } function handleError(f, args) { try { return f.apply(this, args); } catch (e) { wasm.__wbindgen_exn_store(addHeapObject(e)); } } const cachedTextDecoder = (typeof TextDecoder !== 'undefined' ? new TextDecoder('utf-8', { ignoreBOM: true, fatal: true }) : { decode: () => { throw Error('TextDecoder not available') } } ); if (typeof TextDecoder !== 'undefined') { cachedTextDecoder.decode(); }; function getStringFromWasm0(ptr, len) { ptr = ptr >>> 0; return cachedTextDecoder.decode(getUint8ArrayMemory0().subarray(ptr, ptr + len)); } function dropObject(idx) { if (idx < 132) return; heap[idx] = heap_next; heap_next = idx; } function takeObject(idx) { const ret = getObject(idx); dropObject(idx); return ret; } function isLikeNone(x) { return x === undefined || x === null; } const CLOSURE_DTORS = (typeof FinalizationRegistry === 'undefined') ? { register: () => {}, unregister: () => {} } : new FinalizationRegistry(state => { wasm.__wbindgen_export_4.get(state.dtor)(state.a, state.b) }); function makeMutClosure(arg0, arg1, dtor, f) { const state = { a: arg0, b: arg1, cnt: 1, dtor }; const real = (...args) => { // First up with a closure we increment the internal reference // count. This ensures that the Rust closure environment won't // be deallocated while we're invoking it. state.cnt++; const a = state.a; state.a = 0; try { return f(a, state.b, ...args); } finally { if (--state.cnt === 0) { wasm.__wbindgen_export_4.get(state.dtor)(a, state.b); CLOSURE_DTORS.unregister(state); } else { state.a = a; } } }; real.original = state; CLOSURE_DTORS.register(real, state, state); return real; } function debugString(val) { // primitive types const type = typeof val; if (type == 'number' || type == 'boolean' || val == null) { return `${val}`; } if (type == 'string') { return `"${val}"`; } if (type == 'symbol') { const description = val.description; if (description == null) { return 'Symbol'; } else { return `Symbol(${description})`; } } if (type == 'function') { const name = val.name; if (typeof name == 'string' && name.length > 0) { return `Function(${name})`; } else { return 'Function'; } } // objects if (Array.isArray(val)) { const length = val.length; let debug = '['; if (length > 0) { debug += debugString(val[0]); } for(let i = 1; i < length; i++) { debug += ', ' + debugString(val[i]); } debug += ']'; return debug; } // Test for built-in const builtInMatches = /\[object ([^\]]+)\]/.exec(toString.call(val)); let className; if (builtInMatches && builtInMatches.length > 1) { className = builtInMatches[1]; } else { // Failed to match the standard '[object ClassName]' return toString.call(val); } if (className == 'Object') { // we're a user defined class or Object // JSON.stringify avoids problems with cycles, and is generally much // easier than looping through ownProperties of `val`. try { return 'Object(' + JSON.stringify(val) + ')'; } catch (_) { return 'Object'; } } // errors if (val instanceof Error) { return `${val.name}: ${val.message}\n${val.stack}`; } // TODO we could test for more things here, like `Set`s and `Map`s. return className; } function _assertClass(instance, klass) { if (!(instance instanceof klass)) { throw new Error(`expected instance of ${klass.name}`); } } let stack_pointer = 128; function addBorrowedObject(obj) { if (stack_pointer == 1) throw new Error('out of js stack'); heap[--stack_pointer] = obj; return stack_pointer; } function passArray8ToWasm0(arg, malloc) { const ptr = malloc(arg.length * 1, 1) >>> 0; getUint8ArrayMemory0().set(arg, ptr / 1); WASM_VECTOR_LEN = arg.length; return ptr; } function getArrayU8FromWasm0(ptr, len) { ptr = ptr >>> 0; return getUint8ArrayMemory0().subarray(ptr / 1, ptr / 1 + len); } function getArrayJsValueFromWasm0(ptr, len) { ptr = ptr >>> 0; const mem = getDataViewMemory0(); const result = []; for (let i = ptr; i < ptr + 4 * len; i += 4) { result.push(takeObject(mem.getUint32(i, true))); } return result; } /** * Redacts sensitive content in JSON updates within the specified version range. * * This function allows you to share document history while removing potentially sensitive content. * It preserves the document structure and collaboration capabilities while replacing content with * placeholders according to these redaction rules: * * - Preserves delete and move operations * - Replaces text insertion content with the Unicode replacement character * - Substitutes list and map insert values with null * - Maintains structure of child containers * - Replaces text mark values with null * - Preserves map keys and text annotation keys * * @param {Object|string} jsonUpdates - The JSON updates to redact (object or JSON string) * @param {Object} versionRange - Version range defining what content to redact, * format: { peerId: [startCounter, endCounter], ... } * @returns {Object} The redacted JSON updates * @param {string | JsonSchema} json_updates * @param {any} version_range * @returns {JsonSchema} */ export function redactJsonUpdates(json_updates, version_range) { try { const retptr = wasm.__wbindgen_add_to_stack_pointer(-16); wasm.redactJsonUpdates(retptr, addHeapObject(json_updates), addHeapObject(version_range)); var r0 = getDataViewMemory0().getInt32(retptr + 4 * 0, true); var r1 = getDataViewMemory0().getInt32(retptr + 4 * 1, true); var r2 = getDataViewMemory0().getInt32(retptr + 4 * 2, true); if (r2) { throw takeObject(r1); } return takeObject(r0); } finally { wasm.__wbindgen_add_to_stack_pointer(16); } } /** * @param {Uint8Array} bytes * @returns {{ peer: PeerID, counter: number }[]} */ export function decodeFrontiers(bytes) { try { const retptr = wasm.__wbindgen_add_to_stack_pointer(-16); const ptr0 = passArray8ToWasm0(bytes, wasm.__wbindgen_malloc); const len0 = WASM_VECTOR_LEN; wasm.decodeFrontiers(retptr, ptr0, len0); var r0 = getDataViewMemory0().getInt32(retptr + 4 * 0, true); var r1 = getDataViewMemory0().getInt32(retptr + 4 * 1, true); var r2 = getDataViewMemory0().getInt32(retptr + 4 * 2, true); if (r2) { throw takeObject(r1); } return takeObject(r0); } finally { wasm.__wbindgen_add_to_stack_pointer(16); } } function passArrayJsValueToWasm0(array, malloc) { const ptr = malloc(array.length * 4, 4) >>> 0; const mem = getDataViewMemory0(); for (let i = 0; i < array.length; i++) { mem.setUint32(ptr + 4 * i, addHeapObject(array[i]), true); } WASM_VECTOR_LEN = array.length; return ptr; } /** * @param {({ peer: PeerID, counter: number })[]} frontiers * @returns {Uint8Array} */ export function encodeFrontiers(frontiers) { try { const retptr = wasm.__wbindgen_add_to_stack_pointer(-16); const ptr0 = passArrayJsValueToWasm0(frontiers, wasm.__wbindgen_malloc); const len0 = WASM_VECTOR_LEN; wasm.encodeFrontiers(retptr, ptr0, len0); var r0 = getDataViewMemory0().getInt32(retptr + 4 * 0, true); var r1 = getDataViewMemory0().getInt32(retptr + 4 * 1, true); var r2 = getDataViewMemory0().getInt32(retptr + 4 * 2, true); var r3 = getDataViewMemory0().getInt32(retptr + 4 * 3, true); if (r3) { throw takeObject(r2); } var v2 = getArrayU8FromWasm0(r0, r1).slice(); wasm.__wbindgen_free(r0, r1 * 1, 1); return v2; } finally { wasm.__wbindgen_add_to_stack_pointer(16); } } /** * Decode the metadata of the import blob. * * This method is useful to get the following metadata of the import blob: * * - startVersionVector * - endVersionVector * - startTimestamp * - endTimestamp * - mode * - changeNum * @param {Uint8Array} blob * @param {boolean} check_checksum * @returns {ImportBlobMetadata} */ export function decodeImportBlobMeta(blob, check_checksum) { try { const retptr = wasm.__wbindgen_add_to_stack_pointer(-16); const ptr0 = passArray8ToWasm0(blob, wasm.__wbindgen_malloc); const len0 = WASM_VECTOR_LEN; wasm.decodeImportBlobMeta(retptr, ptr0, len0, check_checksum); var r0 = getDataViewMemory0().getInt32(retptr + 4 * 0, true); var r1 = getDataViewMemory0().getInt32(retptr + 4 * 1, true); var r2 = getDataViewMemory0().getInt32(retptr + 4 * 2, true); if (r2) { throw takeObject(r1); } return takeObject(r0); } finally { wasm.__wbindgen_add_to_stack_pointer(16); } } /** * Get the version of Loro * @returns {string} */ export function LORO_VERSION() { let deferred1_0; let deferred1_1; try { const retptr = wasm.__wbindgen_add_to_stack_pointer(-16); wasm.LORO_VERSION(retptr); var r0 = getDataViewMemory0().getInt32(retptr + 4 * 0, true); var r1 = getDataViewMemory0().getInt32(retptr + 4 * 1, true); deferred1_0 = r0; deferred1_1 = r1; return getStringFromWasm0(r0, r1); } finally { wasm.__wbindgen_add_to_stack_pointer(16); wasm.__wbindgen_free(deferred1_0, deferred1_1, 1); } } export function run() { wasm.run(); } export function callPendingEvents() { wasm.callPendingEvents(); } /** * Enable debug info of Loro */ export function setDebug() { wasm.setDebug(); } function __wbg_adapter_60(arg0, arg1, arg2) { wasm._dyn_core__ops__function__FnMut__A____Output___R_as_wasm_bindgen__closure__WasmClosure___describe__invoke__h23bd7b34cf0bced7(arg0, arg1, addHeapObject(arg2)); } function __wbg_adapter_63(arg0, arg1) { wasm._dyn_core__ops__function__FnMut_____Output___R_as_wasm_bindgen__closure__WasmClosure___describe__invoke__hd82b624f21a7fa96(arg0, arg1); } const AwarenessWasmFinalization = (typeof FinalizationRegistry === 'undefined') ? { register: () => {}, unregister: () => {} } : new FinalizationRegistry(ptr => wasm.__wbg_awarenesswasm_free(ptr >>> 0, 1)); /** * `Awareness` is a structure that tracks the ephemeral state of peers. * * It can be used to synchronize cursor positions, selections, and the names of the peers. * * The state of a specific peer is expected to be removed after a specified timeout. Use * `remove_outdated` to eliminate outdated states. */ export class AwarenessWasm { __destroy_into_raw() { const ptr = this.__wbg_ptr; this.__wbg_ptr = 0; AwarenessWasmFinalization.unregister(this); return ptr; } free() { const ptr = this.__destroy_into_raw(); wasm.__wbg_awarenesswasm_free(ptr, 0); } /** * Get the state of all peers. * @returns {{[peer in PeerID]: unknown}} */ getAllStates() { try { const retptr = wasm.__wbindgen_add_to_stack_pointer(-16); wasm.awarenesswasm_getAllStates(retptr, this.__wbg_ptr); var r0 = getDataViewMemory0().getInt32(retptr + 4 * 0, true); var r1 = getDataViewMemory0().getInt32(retptr + 4 * 1, true); var r2 = getDataViewMemory0().getInt32(retptr + 4 * 2, true); if (r2) { throw takeObject(r1); } return takeObject(r0); } finally { wasm.__wbindgen_add_to_stack_pointer(16); } } /** * Get the timestamp of the state of a given peer. * @param {number | bigint | `${number}`} peer * @returns {number | undefined} */ getTimestamp(peer) { try { const retptr = wasm.__wbindgen_add_to_stack_pointer(-32); wasm.awarenesswasm_getTimestamp(retptr, this.__wbg_ptr, addHeapObject(peer)); var r0 = getDataViewMemory0().getInt32(retptr + 4 * 0, true); var r2 = getDataViewMemory0().getFloat64(retptr + 8 * 1, true); var r4 = getDataViewMemory0().getInt32(retptr + 4 * 4, true); var r5 = getDataViewMemory0().getInt32(retptr + 4 * 5, true); if (r5) { throw takeObject(r4); } return r0 === 0 ? undefined : r2; } finally { wasm.__wbindgen_add_to_stack_pointer(32); } } /** * Sets the state of the local peer. * @param {any} value */ setLocalState(value) { wasm.awarenesswasm_setLocalState(this.__wbg_ptr, addHeapObject(value)); } /** * Remove the states of outdated peers. * @returns {PeerID[]} */ removeOutdated() { try { const retptr = wasm.__wbindgen_add_to_stack_pointer(-16); wasm.awarenesswasm_removeOutdated(retptr, this.__wbg_ptr); var r0 = getDataViewMemory0().getInt32(retptr + 4 * 0, true); var r1 = getDataViewMemory0().getInt32(retptr + 4 * 1, true); var v1 = getArrayJsValueFromWasm0(r0, r1).slice(); wasm.__wbindgen_free(r0, r1 * 4, 4); return v1; } finally { wasm.__wbindgen_add_to_stack_pointer(16); } } /** * Creates a new `Awareness` instance. * * The `timeout` parameter specifies the duration in milliseconds. * A state of a peer is considered outdated, if the last update of the state of the peer * is older than the `timeout`. * @param {number | bigint | `${number}`} peer * @param {number} timeout */ constructor(peer, timeout) { try { const retptr = wasm.__wbindgen_add_to_stack_pointer(-16); wasm.awarenesswasm_new(retptr, addHeapObject(peer), timeout); var r0 = getDataViewMemory0().getInt32(retptr + 4 * 0, true); var r1 = getDataViewMemory0().getInt32(retptr + 4 * 1, true); var r2 = getDataViewMemory0().getInt32(retptr + 4 * 2, true); if (r2) { throw takeObject(r1); } this.__wbg_ptr = r0 >>> 0; AwarenessWasmFinalization.register(this, this.__wbg_ptr, this); return this; } finally { wasm.__wbindgen_add_to_stack_pointer(16); } } /** * Get the PeerID of the local peer. * @returns {PeerID} */ peer() { const ret = wasm.awarenesswasm_peer(this.__wbg_ptr); return takeObject(ret); } /** * Applies the encoded state of peers. * * Each peer's deletion countdown will be reset upon update, requiring them to pass through the `timeout` * interval again before being eligible for deletion. * @param {Uint8Array} encoded_peers_info * @returns {{ updated: PeerID[], added: PeerID[] }} */ apply(encoded_peers_info) { try { const retptr = wasm.__wbindgen_add_to_stack_pointer(-16); const ptr0 = passArray8ToWasm0(encoded_peers_info, wasm.__wbindgen_malloc); const len0 = WASM_VECTOR_LEN; wasm.awarenesswasm_apply(retptr, this.__wbg_ptr, ptr0, len0); var r0 = getDataViewMemory0().getInt32(retptr + 4 * 0, true); var r1 = getDataViewMemory0().getInt32(retptr + 4 * 1, true); var r2 = getDataViewMemory0().getInt32(retptr + 4 * 2, true); if (r2) { throw takeObject(r1); } return takeObject(r0); } finally { wasm.__wbindgen_add_to_stack_pointer(16); } } /** * Get all the peers * @returns {PeerID[]} */ peers() { try { const retptr = wasm.__wbindgen_add_to_stack_pointer(-16); wasm.awarenesswasm_peers(retptr, this.__wbg_ptr); var r0 = getDataViewMemory0().getInt32(retptr + 4 * 0, true); var r1 = getDataViewMemory0().getInt32(retptr + 4 * 1, true); var v1 = getArrayJsValueFromWasm0(r0, r1).slice(); wasm.__wbindgen_free(r0, r1 * 4, 4); return v1; } finally { wasm.__wbindgen_add_to_stack_pointer(16); } } /** * Encodes the state of the given peers. * @param {Array<any>} peers * @returns {Uint8Array} */ encode(peers) { try { const retptr = wasm.__wbindgen_add_to_stack_pointer(-16); wasm.awarenesswasm_encode(retptr, this.__wbg_ptr, addHeapObject(peers)); var r0 = getDataViewMemory0().getInt32(retptr + 4 * 0, true); var r1 = getDataViewMemory0().getInt32(retptr + 4 * 1, true); var r2 = getDataViewMemory0().getInt32(retptr + 4 * 2, true); var r3 = getDataViewMemory0().getInt32(retptr + 4 * 3, true); if (r3) { throw takeObject(r2); } var v1 = getArrayU8FromWasm0(r0, r1).slice(); wasm.__wbindgen_free(r0, r1 * 1, 1); return v1; } finally { wasm.__wbindgen_add_to_stack_pointer(16); } } /** * Get the number of peers. * @returns {number} */ length() { const ret = wasm.awarenesswasm_length(this.__wbg_ptr); return ret; } /** * If the state is empty. * @returns {boolean} */ isEmpty() { const ret = wasm.awarenesswasm_isEmpty(this.__wbg_ptr); return ret !== 0; } /** * Get the state of a given peer. * @param {number | bigint | `${number}`} peer * @returns {any} */ getState(peer) { try { const retptr = wasm.__wbindgen_add_to_stack_pointer(-16); wasm.awarenesswasm_getState(retptr, this.__wbg_ptr, addHeapObject(peer)); var r0 = getDataViewMemory0().getInt32(retptr + 4 * 0, true); var r1 = getDataViewMemory0().getInt32(retptr + 4 * 1, true); var r2 = getDataViewMemory0().getInt32(retptr + 4 * 2, true); if (r2) { throw takeObject(r1); } return takeObject(r0); } finally { wasm.__wbindgen_add_to_stack_pointer(16); } } /** * Encodes the state of all peers. * @returns {Uint8Array} */ encodeAll() { try { const retptr = wasm.__wbindgen_add_to_stack_pointer(-16); wasm.awarenesswasm_encodeAll(retptr, this.__wbg_ptr); var r0 = getDataViewMemory0().getInt32(retptr + 4 * 0, true); var r1 = getDataViewMemory0().getInt32(retptr + 4 * 1, true); var v1 = getArrayU8FromWasm0(r0, r1).slice(); wasm.__wbindgen_free(r0, r1 * 1, 1); return v1; } finally { wasm.__wbindgen_add_to_stack_pointer(16); } } } const ChangeModifierFinalization = (typeof FinalizationRegistry === 'undefined') ? { register: () => {}, unregister: () => {} } : new FinalizationRegistry(ptr => wasm.__wbg_changemodifier_free(ptr >>> 0, 1)); export class ChangeModifier { static __wrap(ptr) { ptr = ptr >>> 0; const obj = Object.create(ChangeModifier.prototype); obj.__wbg_ptr = ptr; ChangeModifierFinalization.register(obj, obj.__wbg_ptr, obj); return obj; } __destroy_into_raw() { const ptr = this.__wbg_ptr; this.__wbg_ptr = 0; ChangeModifierFinalization.unregister(this); return ptr; } free() { const ptr = this.__destroy_into_raw(); wasm.__wbg_changemodifier_free(ptr, 0); } /** * @param {string} message * @returns {ChangeModifier} */ setMessage(message) { const ptr0 = passStringToWasm0(message, wasm.__wbindgen_malloc, wasm.__wbindgen_realloc); const len0 = WASM_VECTOR_LEN; const ret = wasm.changemodifier_setMessage(this.__wbg_ptr, ptr0, len0); return ChangeModifier.__wrap(ret); } /** * @param {number} timestamp * @returns {ChangeModifier} */ setTimestamp(timestamp) { const ret = wasm.changemodifier_setTimestamp(this.__wbg_ptr, timestamp); return ChangeModifier.__wrap(ret); } } const CursorFinalization = (typeof FinalizationRegistry === 'undefined') ? { register: () => {}, unregister: () => {} } : new FinalizationRegistry(ptr => wasm.__wbg_cursor_free(ptr >>> 0, 1)); /** * Cursor is a stable position representation in the doc. * When expressing the position of a cursor, using "index" can be unstable * because the cursor's position may change due to other deletions and insertions, * requiring updates with each edit. To stably represent a position or range within * a list structure, we can utilize the ID of each item/character on List CRDT or * Text CRDT for expression. * * Loro optimizes State metadata by not storing the IDs of deleted elements. This * approach complicates tracking cursors since they rely on these IDs. The solution * recalculates position by replaying relevant history to update cursors * accurately. To minimize the performance impact of history replay, the system * updates cursor info to reference only the IDs of currently present elements, * thereby reducing the need for replay. * * @example * ```ts * * const doc = new LoroDoc(); * const text = doc.getText("text"); * text.insert(0, "123"); * const pos0 = text.getCursor(0, 0); * { * const ans = doc.getCursorPos(pos0!); * expect(ans.offset).toBe(0); * } * text.insert(0, "1"); * { * const ans = doc.getCursorPos(pos0!); * expect(ans.offset).toBe(1); * } * ``` */ export class Cursor { static __wrap(ptr) { ptr = ptr >>> 0; const obj = Object.create(Cursor.prototype); obj.__wbg_ptr = ptr; CursorFinalization.register(obj, obj.__wbg_ptr, obj); return obj; } __destroy_into_raw() { const ptr = this.__wbg_ptr; this.__wbg_ptr = 0; CursorFinalization.unregister(this); return ptr; } free() { const ptr = this.__destroy_into_raw(); wasm.__wbg_cursor_free(ptr, 0); } /** * Get the id of the given container. * @returns {ContainerID} */ containerId() { const ret = wasm.cursor_containerId(this.__wbg_ptr); return takeObject(ret); } /** * Get the ID that represents the position. * * It can be undefined if it's not bind into a specific ID. * @returns {{ peer: PeerID, counter: number } | undefined} */ pos() { try { const retptr = wasm.__wbindgen_add_to_stack_pointer(-16); wasm.cursor_pos(retptr, this.__wbg_ptr); var r0 = getDataViewMemory0().getInt32(retptr + 4 * 0, true); var r1 = getDataViewMemory0().getInt32(retptr + 4 * 1, true); var r2 = getDataViewMemory0().getInt32(retptr + 4 * 2, true); if (r2) { throw takeObject(r1); } return takeObject(r0); } finally { wasm.__wbindgen_add_to_stack_pointer(16); } } /** * "Cursor" * @returns {any} */ kind() { const ret = wasm.cursor_kind(this.__wbg_ptr); return takeObject(ret); } /** * Get which side of the character/list item the cursor is on. * @returns {Side} */ side() { const ret = wasm.cursor_side(this.__wbg_ptr); return takeObject(ret); } /** * Decode the cursor from a Uint8Array. * @param {Uint8Array} data * @returns {Cursor} */ static decode(data) { try { const retptr = wasm.__wbindgen_add_to_stack_pointer(-16); const ptr0 = passArray8ToWasm0(data, wasm.__wbindgen_malloc); const len0 = WASM_VECTOR_LEN; wasm.cursor_decode(retptr, ptr0, len0); var r0 = getDataViewMemory0().getInt32(retptr + 4 * 0, true); var r1 = getDataViewMemory0().getInt32(retptr + 4 * 1, true); var r2 = getDataViewMemory0().getInt32(retptr + 4 * 2, true); if (r2) { throw takeObject(r1); } return Cursor.__wrap(r0); } finally { wasm.__wbindgen_add_to_stack_pointer(16); } } /** * Encode the cursor into a Uint8Array. * @returns {Uint8Array} */ encode() { try { const retptr = wasm.__wbindgen_add_to_stack_pointer(-16); wasm.cursor_encode(retptr, this.__wbg_ptr); var r0 = getDataViewMemory0().getInt32(retptr + 4 * 0, true); var r1 = getDataViewMemory0().getInt32(retptr + 4 * 1, true); var v1 = getArrayU8FromWasm0(r0, r1).slice(); wasm.__wbindgen_free(r0, r1 * 1, 1); return v1; } finally { wasm.__wbindgen_add_to_stack_pointer(16); } } } const EphemeralStoreWasmFinalization = (typeof FinalizationRegistry === 'undefined') ? { register: () => {}, unregister: () => {} } : new FinalizationRegistry(ptr => wasm.__wbg_ephemeralstorewasm_free(ptr >>> 0, 1)); export class EphemeralStoreWasm { __destroy_into_raw() { const ptr = this.__wbg_ptr; this.__wbg_ptr = 0; EphemeralStoreWasmFinalization.unregister(this); return ptr; } free() { const ptr = this.__destroy_into_raw(); wasm.__wbg_ephemeralstorewasm_free(ptr, 0); } /** * @returns {any} */ getAllStates() { try { const retptr = wasm.__wbindgen_add_to_stack_pointer(-16); wasm.ephemeralstorewasm_getAllStates(retptr, this.__wbg_ptr); var r0 = getDataViewMemory0().getInt32(retptr + 4 * 0, true); var r1 = getDataViewMemory0().getInt32(retptr + 4 * 1, true); var r2 = getDataViewMemory0().getInt32(retptr + 4 * 2, true); if (r2) { throw takeObject(r1); } return takeObject(r0); } finally { wasm.__wbindgen_add_to_stack_pointer(16); } } removeOutdated() { wasm.ephemeralstorewasm_removeOutdated(this.__wbg_ptr); } /** * @param {Function} f * @returns {any} */ subscribeLocalUpdates(f) { const ret = wasm.ephemeralstorewasm_subscribeLocalUpdates(this.__wbg_ptr, addHeapObject(f)); return takeObject(ret); } /** * @param {string} key * @returns {any} */ get(key) { const ptr0 = passStringToWasm0(key, wasm.__wbindgen_malloc, wasm.__wbindgen_realloc); const len0 = WASM_VECTOR_LEN; const ret = wasm.ephemeralstorewasm_get(this.__wbg_ptr, ptr0, len0); return takeObject(ret); } /** * Creates a new `EphemeralStore` instance. * * The `timeout` parameter specifies the duration in milliseconds. * A state of a peer is considered outdated, if the last update of the state of the peer * is older than the `timeout`. * @param {number} timeout */ constructor(timeout) { const ret = wasm.ephemeralstorewasm_new(timeout); this.__wbg_ptr = ret >>> 0; EphemeralStoreWasmFinalization.register(this, this.__wbg_ptr, this); return this; } /** * @param {string} key * @param {any} value */ set(key, value) { const ptr0 = passStringToWasm0(key, wasm.__wbindgen_malloc, wasm.__wbindgen_realloc); const len0 = WASM_VECTOR_LEN; wasm.ephemeralstorewasm_set(this.__wbg_ptr, ptr0, len0, addHeapObject(value)); } /** * @returns {string[]} */ keys() { try { const retptr = wasm.__wbindgen_add_to_stack_pointer(-16); wasm.ephemeralstorewasm_keys(retptr, this.__wbg_ptr); var r0 = getDataViewMemory0().getInt32(retptr + 4 * 0, true); var r1 = getDataViewMemory0().getInt32(retptr + 4 * 1, true); var v1 = getArrayJsValueFromWasm0(r0, r1).slice(); wasm.__wbindgen_free(r0, r1 * 4, 4); return v1; } finally { wasm.__wbindgen_add_to_stack_pointer(16); } } /** * @param {Uint8Array} data */ apply(data) { try { const retptr = wasm.__wbindgen_add_to_stack_pointer(-16); const ptr0 = passArray8ToWasm0(data, wasm.__wbindgen_malloc); const len0 = WASM_VECTOR_LEN; wasm.ephemeralstorewasm_apply(retptr, this.__wbg_ptr, ptr0, len0); var r0 = getDataViewMemory0().getInt32(retptr + 4 * 0, true); var r1 = getDataViewMemory0().getInt32(retptr + 4 * 1, true); if (r1) { throw takeObject(r0); } } finally { wasm.__wbindgen_add_to_stack_pointer(16); } } /** * @param {string} key */ delete(key) { const ptr0 = passStringToWasm0(key, wasm.__wbindgen_malloc, wasm.__wbindgen_realloc); const len0 = WASM_VECTOR_LEN; wasm.ephemeralstorewasm_delete(this.__wbg_ptr, ptr0, len0); } /** * @param {string} key * @returns {Uint8Array} */ encode(key) { try { const retptr = wasm.__wbindgen_add_to_stack_pointer(-16); const ptr0 = passStringToWasm0(key, wasm.__wbindgen_malloc, wasm.__wbindgen_realloc); const len0 = WASM_VECTOR_LEN; wasm.ephemeralstorewasm_encode(retptr, this.__wbg_ptr, ptr0, len0); var r0 = getDataViewMemory0().getInt32(retptr + 4 * 0, true); var r1 = getDataViewMemory0().getInt32(retptr + 4 * 1, true); var v2 = getArrayU8FromWasm0(r0, r1).slice(); wasm.__wbindgen_free(r0, r1 * 1, 1); return v2; } finally { wasm.__wbindgen_add_to_stack_pointer(16); } } /** * If the state is empty. * @returns {boolean} */ isEmpty() { const ret = wasm.ephemeralstorewasm_isEmpty(this.__wbg_ptr); return ret !== 0; } /** * @returns {Uint8Array} */ encodeAll() { try { const retptr = wasm.__wbindgen_add_to_stack_pointer(-16); wasm.ephemeralstorewasm_encodeAll(retptr, this.__wbg_ptr); var r0 = getDataViewMemory0().getInt32(retptr + 4 * 0, true); var r1 = getDataViewMemory0().getInt32(retptr + 4 * 1, true); var v1 = getArrayU8FromWasm0(r0, r1).slice(); wasm.__wbindgen_free(r0, r1 * 1, 1); return v1; } finally { wasm.__wbindgen_add_to_stack_pointer(16); } } /** * @param {Function} f * @returns {any} */ subscribe(f) { const ret = wasm.ephemeralstorewasm_subscribe(this.__wbg_ptr, addHeapObject(f)); return takeObject(ret); } } const LoroCounterFinalization = (typeof FinalizationRegistry === 'undefined') ? { register: () => {}, unregister: () => {} } : new FinalizationRegistry(ptr => wasm.__wbg_lorocounter_free(ptr >>> 0, 1)); /** * The handler of a counter container. */ export class LoroCounter { static __wrap(ptr) { ptr = ptr >>> 0; const obj = Object.create(LoroCounter.prototype); obj.__wbg_ptr = ptr; LoroCounterFinalization.register(obj, obj.__wbg_ptr, obj); return obj; } __destroy_into_raw() { const ptr = this.__wbg_ptr; this.__wbg_ptr = 0; LoroCounterFinalization.unregister(this); return ptr; } free() { const ptr = this.__destroy_into_raw(); wasm.__wbg_lorocounter_free(ptr, 0); } /** * Whether the container is attached to a docuemnt. * * If it's detached, the operations on the container will not be persisted. * @returns {boolean} */ isAttached() { const ret = wasm.lorocounter_isAttached(this.__wbg_ptr); return ret !== 0; } /** * Get the attached container associated with this. * * Returns an attached `Container` that equals to this or created by this, otherwise `undefined`. * @returns {LoroTree | undefined} */ getAttached() { const ret = wasm.lorocounter_getAttached(this.__wbg_ptr); return takeObject(ret); } /** * Get the value of the counter. * @returns {number} */ getShallowValue() { try { const retptr = wasm.__wbindgen_add_to_stack_pointer(-16); wasm.lorocounter_getShallowValue(retptr, this.__wbg_ptr); var r0 = getDataViewMemory0().getFloat64(retptr + 8 * 0, true); var r2 = getDataViewMemory0().getInt32(retptr + 4 * 2, true); var r3 = getDataViewMemory0().getInt32(retptr + 4 * 3, true); if (r3) { throw takeObject(r2); } return r0; } finally { wasm.__wbindgen_add_to_stack_pointer(16); } } /** * The container id of this handler. * @returns {ContainerID} */ get id() { const ret = wasm.lorocounter_id(this.__wbg_ptr); return takeObject(ret); } /** * Create a new LoroCounter. */ constructor() { const ret = wasm.lorocounter_new(); this.__wbg_ptr = ret >>> 0; LoroCounterFinalization.register(this, this.__wbg_ptr, this); return this; } /** * "Counter" * @returns {'Counter'} */ kind() { const ret = wasm.lorocounter_kind(this.__wbg_ptr); return takeObject(ret); } /** * Get the parent container of the counter container. * * - The parent container of the root counter is `undefined`. * - The object returned is a new js object each time because it need to cross * the WASM boundary. * @returns {Container | undefined} */ parent() { const ret = wasm.lorocounter_parent(this.__wbg_ptr); return takeObject(ret); } /** * @returns {number} */ toJSON() { try { const retptr = wasm.__wbindgen_add_to_stack_pointer(-16); wasm.lorocounter_getShallowValue(retptr, this.__wbg_ptr); var r0 = getDataViewMemory0().getFloat64(retptr + 8 * 0, true); var r2 = getDataViewMemory0().getInt32(retptr + 4 * 2, true); var r3 = getDataViewMemory0().getInt32(retptr + 4 * 3, true); if (r3) { throw takeObject(r2); } return r0; } finally { wasm.__wbindgen_add_to_stack_pointer(16); } } /** * Decrement the counter by the given value. * @param {number} value */ decrement(value) { try { const retptr = wasm.__wbindgen_add_to_stack_pointer(-16); wasm.lorocounter_decrement(retptr, this.__wbg_ptr, value); var r0 = getDataViewMemory0().getInt32(retptr + 4 * 0, true); var r1 = getDataViewMemory0().getInt32(retptr + 4 * 1, true); if (r1) { throw takeObject(r0); } } finally { wasm.__wbindgen_add_to_stack_pointer(16); } } /** * Get the value of the counter. * @returns {number} */ get value() { try { const retptr = wasm.__wbindgen_add_to_stack_pointer(-16); wasm.lorocounter_getShallowValue(retptr, this.__wbg_ptr); var r0 = getDataViewMemory0().getFloat64(retptr + 8 * 0, true); var r2 = getDataViewMemory0().getInt32(retptr + 4 * 2, true); var r3 = getDataViewMemory0().getInt32(retptr + 4 * 3, true); if (r3) { throw takeObject(r2); } return r0; } finally { wasm.__wbindgen_add_to_stack_pointer(16); } } /** * Increment the counter by the given value. * @param {number} value */ increment(value) { try { const retptr = wasm.__wbindgen_add_to_stack_pointer(-16); wasm.lorocounter_increment(retptr, this.__wbg_ptr, value); var r0 = getDataViewMemory0().getInt32(retptr + 4 * 0, true); var r1 = getDataViewMemory0().getInt32(retptr + 4 * 1, true); if (r1) { throw takeObject(r0); } } finally { wasm.__wbindgen_add_to_stack_pointer(16); } } /** * Subscribe to the changes of the counter. * @param {Function} f * @returns {any} */ subscribe(f) { try { const retptr = wasm.__wbindgen_add_to_stack_pointer(-16); wasm.lorocounter_subscribe(retptr, this.__wbg_ptr, addHeapObject(f)); var r0 = getDataViewMemory0().getInt32(retptr + 4 * 0, true); var r1 = getDataViewMemory0().getInt32(retptr + 4 * 1, true); var r2 = getDataViewMemory0().getInt32(retptr + 4 * 2, true); if (r2) { throw takeObject(r1); } return takeObject(r0); } finally { wasm.__wbindgen_add_to_stack_pointer(16); } } } const LoroDocFinalization = (typeof FinalizationRegistry === 'undefined') ? { register: () => {}, unregister: () => {} } : new FinalizationRegistry(ptr => wasm.__wbg_lorodoc_free(ptr >>> 0, 1)); /** * The CRDTs document. Loro supports different CRDTs include [**List**](LoroList), * [**RichText**](LoroText), [**Map**](LoroMap) and [**Movable Tree**](LoroTree), * you could build all kind of applications by these. * * **Important:** Loro is a pure library and does not handle network protocols. * It is the responsibility of the user to manage the storage, loading, and synchronization * of the bytes exported by Loro in a manner suitable for their specific environment. * * @example * ```ts * import { LoroDoc } from "loro-crdt" * * const loro = new LoroDoc(); * const text = loro.getText("text"); * const list = loro.getList("list"); * const map = loro.getMap("Map"); * const tree = loro.getTree("tree"); * ``` */ export class LoroDoc { static __wrap(ptr) { ptr = ptr >>> 0; const obj = Object.create(LoroDoc.prototype); obj.__wbg_ptr = ptr; LoroDocFinalization.register(obj, obj.__wbg_ptr, obj); return obj; } __destroy_into_raw() { const ptr = this.__wbg_ptr; this.__wbg_ptr = 0; LoroDocFinalization.unregister(this); return ptr; } free() { const ptr = this.__destroy_into_raw(); wasm.__wbg_lorodoc_free(ptr, 0); } /** * Apply a batch of diff to the document * * A diff batch represents a set of changes between two versions of the document. * You can calculate a diff batch using `doc.diff()`. * * Changes are associated with container IDs. During diff application, if new containers were created in the source * document, they will be assigned fresh IDs in the target document. Loro automatically handles remapping these * container IDs from their original IDs to the new IDs as the diff is applied. * * @example * ```ts * const doc1 = new LoroDoc(); * const doc2 = new LoroDoc(); * * // Make some changes to doc1 * const text = doc1.getText("text"); * text.insert(0, "Hello"); * * // Calculate diff between empty and current state * const diff = doc1.diff([], doc1.frontiers()); * * // Apply changes to doc2 * doc2.applyDiff(diff); * console.log(doc2.getText("text").toString()); // "Hello" * ``` * @param {[ContainerID, Diff|JsonDiff][]} diff */ applyDiff(diff) { try { const retptr = wasm.__wbindgen_add_to_stack_pointer(-16); wasm.lorodoc_applyDiff(retptr, this.__wbg_ptr, addHeapObject(diff)); var r0 = getDataViewMemory0().getInt32(retptr + 4 * 0, true); var r1 = getDataViewMemory0().getInt32(retptr + 4 * 1, true); if (r1) { throw takeObject(r0); } } finally { wasm.__wbindgen_add_to_stack_pointer(16); } } /** * Check if the doc contains the full history. * @returns {boolean} */ isShallow() { const ret = wasm.lorodoc_isShallow(this.__wbg_ptr); return ret !== 0; } /** * Get the number of changes in the oplog. * @returns {number} */ changeCount() { const ret = wasm.lorodoc_changeCount(this.__wbg_ptr); return ret >>> 0; } /** * Get the value or container at the given path * * The path can be specified in different ways depending on the container type: * * For Tree: * 1. Using node IDs: `tree/{node_id}/property` * 2. Using indices: `tree/0/1/property` * * For List and MovableList: * - Using indices: `list/0` or `list/1/property` * * For Map: * - Using keys: `map/key` or `map/nested/property` * * For tree structures, index-based paths follow depth-first traversal order. * The indices start from 0 and represent the position of a node among its siblings. * * @example * ```ts * import { LoroDoc } from "loro-crdt"; * * const doc = new LoroDoc(); * const map = doc.getMap("map"); * map.set("key", 1); * console.log(doc.getByPath("map/key")); // 1 * console.log(doc.getByPath("map")); // LoroMap * ``` * @param {string} path * @returns {Value | Container | undefined} */ getByPath(path) { const ptr0 = passStringToWasm0(path, wasm.__wbindgen_malloc, wasm.__wbindgen_realloc); const len0 = WASM_VECTOR_LEN; const ret = wasm.lorodoc_getByPath(this.__wbg_ptr, ptr0, len0); return takeObject(ret); } /** * Get a LoroCounter by container id * * If the container does not exist, an error will be thrown. * @param {ContainerID | string} cid * @returns {LoroCounter} */ getCounter(cid) { try { const retptr = wasm.__wbindgen_add_to_stack_pointer(-16); wasm.lorodoc_getCounter(retptr, this.__wbg_ptr, addBorrowedObject(cid)); var r0 = getDataViewMemory0().getInt32(retptr + 4 * 0, true); var r1 = getDataViewMemory0().getInt32(retptr + 4 * 1, true); var r2 = getDataViewMemory0().getInt32(retptr + 4 * 2, true); if (r2) { throw takeObject(r1); } return LoroCounter.__wrap(r0); } finally { wasm.__wbindgen_add_to_stack_pointer(16); heap[stack_pointer++] = undefined; } } /** * `detached` indicates that the `DocState` is not synchronized with the latest version of `OpLog`. * * > The document becomes detached during a `checkout` operation. * > Being `detached` implies that the `DocState` is not synchronized with the latest version of the `OpLog`. * > In a detached state, the document is not editable by default, and any `import` operations will be * > recorded in the `OpLog` without being applied to the `DocState`. * * @example * ```ts * import { LoroDoc } from "loro-crdt"; * * const doc = new LoroDoc(); * const text = doc.getText("text"); * const frontiers = doc.frontiers(); * text.insert(0, "Hello World!"); * console.log(doc.isDetached()); // false * doc.checkout(frontiers); * console.log(doc.isDetached()); // true * doc.attach(); * console.log(doc.isDetached()); // false * ``` * @returns {boolean} */ isDetached() { const ret = wasm.lorodoc_isDetached(this.__wbg_ptr); return ret !== 0; } /** * Get peer id in decimal string. * @returns {PeerID} */ get peerIdStr() { const ret = wasm.lorodoc_peerIdStr(this.__wbg_ptr); return takeObject(ret); } /** * Set the peer ID of the current writer. * * It must be a number, a BigInt, or a decimal string that can be parsed to a unsigned 64-bit integer. * * Note: use it with caution. You need to make sure there is not chance that two peers * have the same peer ID. Otherwise, we cannot ensure the consistency of the document. * @param {number | bigint | `${number}`} peer_id */ setPeerId(peer_id) { try { const retptr = wasm.__wbindgen_add_to_stack_pointer(-16); wasm.lorodoc_setPeerId(retptr, this.__wbg_ptr, addHeapObject(peer_id)); var r0 = getDataViewMemory0().getInt32(retptr + 4 * 0, true); var r1 = getDataViewMemory0().getInt32(retptr + 4 * 1, true); if (r1) { throw takeObject(r0); } } finally { wasm.__wbindgen_add_to_stack_pointer(16); } } /** * Get the absolute position of the given Cursor * * @example * ```ts * const doc = new LoroDoc(); * const text = doc.getText("text"); * text.insert(0, "123"); * const pos0 = text.getCursor(0, 0); * { * const ans = doc.getCursorPos(pos0!); * expect(ans.offset).toBe(0); * } * text.insert(0, "1"); * { * const ans = doc.getCursorPos(pos0!); * expect(ans.offset).toBe(1); * } * ``` * @param {Cursor} cursor * @returns {{ update?: Cursor, offset: number, side: Side } | undefined} */ getCursorPos(cursor) { try { const retptr = wasm.__wbindgen_add_to_stack_pointer(-16); _assertClass(cursor, Cursor); wasm.lorodoc_getCursorPos(retptr, this.__wbg_ptr, cursor.__wbg_ptr); var r0 = getDataViewMemory0().getInt32(retptr + 4 * 0, true); var r1 = getDataViewMemory0().getInt32(retptr + 4 * 1, true); var r2 = getDataViewMemory0().getInt32(retptr + 4 * 2, true); if (r2) { throw takeObject(r1); } return takeObject(r0); } finally { wasm.__wbindgen_add_to_stack_pointer(16); } } /** * Check if the doc contains the target container. * * A root container always exists, while a normal container exists * if it has ever been created on the doc. * * @example * ```ts * import { LoroDoc, LoroMap, LoroText, LoroList } from "loro-crdt"; * * const doc = new LoroDoc(); * doc.setPeerId("1"); * const text = doc.getMap("map").setContainer("text", new LoroText()); * const list = doc.getMap("map").setContainer("list", new LoroList()); * expect(doc.isContainerExists("cid:root-map:Map")).toBe(true); * expect(doc.isContainerExists("cid:0@1:Te