carnelia-wasm-sdk
JavaScript/TypeScript-facing WebAssembly bindings for MDCS collaborative CRDT documents, presence, and offline-first merge in browsers.
用 Codex 或 Claude 帮你安装 复制这段 Prompt,粘贴到 Codex、Claude 或其他助手里,让它检查 Skill 页面并帮你完成安装。
菜单
JavaScript/TypeScript-facing WebAssembly bindings for MDCS collaborative CRDT documents, presence, and offline-first merge in browsers.
用 Codex 或 Claude 帮你安装 复制这段 Prompt,粘贴到 Codex、Claude 或其他助手里,让它检查 Skill 页面并帮你完成安装。
| name | carnelia-wasm-sdk |
| description | JavaScript/TypeScript-facing WebAssembly bindings for MDCS collaborative CRDT documents, presence, and offline-first merge in browsers. |
| metadata | null |
| tags | wasm, javascript, typescript, crdt, collaborative, rich-text, json, presence, browser, mdcs |
mdcs-wasm)WebAssembly bindings for using MDCS CRDTs from JavaScript/TypeScript in browser apps. Exposes ergonomic document APIs for rich text, plain text, and JSON collaboration, plus user-presence helpers and utility functions.
Internal crate dependencies: mdcs-core (lattice join), mdcs-db (RichText, RGAText, JsonCrdt, mark and JSON types), serde_wasm_bindgen (JS<->Rust serialization), wasm-bindgen/js-sys/web-sys.
Activate this skill when the user is:
CollaborativeDocument, TextDocument, RichTextDocument, or JsonDocumentUserPresenceThe WASM SDK is a bindings layer over mdcs-db CRDT implementations, exposing JS-callable classes via #[wasm_bindgen].
| Binding | Responsibility | Core Backing Type |
|---|---|---|
CollaborativeDocument | Rich-text collaborative editing + formatting marks | mdcs_db::RichText |
TextDocument | Plain-text collaborative editing API | mdcs_db::RGAText |
RichTextDocument | Explicit rich-text wrapper (SDK-style naming) | wraps CollaborativeDocument |
JsonDocument | Collaborative JSON CRDT operations (dot-path + arrays) | mdcs_db::JsonCrdt |
UserPresence | Cursor/selection/user metadata helper for UI | Plain Rust struct serialized via Serde |
| Utility fns | Runtime and UX helpers | init_panic_hook, generate_replica_id, generate_user_color, console_log |
Lattice::join on underlying CRDT states (join is commutative, associative, idempotent)| Function | Signature | Notes |
|---|---|---|
init_panic_hook | () -> void | #[wasm_bindgen(start)]; enables better panic messages when feature enabled |
generate_replica_id | () -> string | Timestamp + random bits string |
generate_user_color | () -> string | Picks from fixed 16-color palette |
console_log | (message: string) -> void | Writes to browser console |
CollaborativeDocumentRich-text collaborative document with formatting support and CRDT merge.
| Method | Signature | Notes |
|---|---|---|
new | (doc_id: string, replica_id: string) | Constructor |
insert | (position: number, text: string) | Clamps to current length |
delete | (position: number, length: number) | Safe clamped delete |
apply_bold / apply_italic / apply_underline / apply_strikethrough / apply_code | (start: number, end: number) | Applies corresponding MarkType |
apply_link | (start: number, end: number, url: string) | Link mark |
apply_highlight | (start: number, end: number, color: string) | Highlight mark |
apply_comment | (start: number, end: number, author: string, content: string) | Comment mark |
apply_custom_mark | (start: number, end: number, name: string, value: string) | Custom mark |
get_text | () -> string | Plain text projection |
get_html | () -> string | HTML rendering from RichText |
len | () -> number | Character length |
is_empty | () -> boolean | |
version | () -> number | Local monotonic counter |
doc_id | () -> string | Returns cloned ID |
replica_id | () -> string | Returns cloned replica ID |
serialize | () -> Result<string, JsValue> | JSON string of serialized RichText state |
merge | (remote_state: string) -> Result<void, JsValue> | Parses remote JSON and joins state |
snapshot | () -> Result<JsValue, JsValue> | { doc_id, replica_id, version, state } |
restore | (snapshot: JsValue) -> Result<CollaborativeDocument, JsValue> | Rehydrates document from snapshot |
TextDocumentPlain-text collaborative wrapper over RGAText.
| Method | Signature | Notes |
|---|---|---|
new | (doc_id: string, replica_id: string) | Constructor |
insert | (position: number, text: string) | Clamped position |
delete | (position: number, length: number) | Clamped delete |
replace | (start: number, end: number, text: string) | Delegates to RGAText::replace |
splice | (position: number, delete_count: number, insert: string) | Delegates to RGAText::splice |
get_text | () -> string | |
len | () -> number | |
is_empty | () -> boolean | |
version | () -> number | |
doc_id / replica_id | () -> string | |
serialize | () -> Result<string, JsValue> | JSON string |
merge | (remote_state: string) -> Result<void, JsValue> | CRDT join |
snapshot / restore | Snapshot object roundtrip | Same shape as CollaborativeDocument |
RichTextDocumentNaming wrapper around CollaborativeDocument (delegates all methods).
| Method Surface | Notes |
|---|---|
Constructors, edit ops, format ops, reads, ids, serialize, merge, snapshot, restore | Fully forwarded to internal CollaborativeDocument |
Use this when API naming clarity matters (RichTextDocument) but behavior should match CollaborativeDocument exactly.
JsonDocumentCollaborative JSON CRDT with dot-path convenience and typed setters.
| Method | Signature | Notes |
|---|---|---|
new | (doc_id: string, replica_id: string) | Constructor |
set_string / set_int / set_float / set_bool / set_null | (path: string, value?) -> Result<void, JsValue> | Uses JsonPath::parse(path) |
set_object / set_array | (path: string) -> Result<void, JsValue> | Creates object/array node |
array_push_string / array_push_int / array_push_float / array_push_bool / array_push_null | (path: string, value?) -> Result<void, JsValue> | Requires path to existing array |
array_remove | (path: string, index: number) -> Result<JsValue, JsValue> | Returns removed primitive JSON value or placeholder for complex references |
delete | (path: string) -> Result<void, JsValue> | Deletes node |
get | (path: string) -> Result<JsValue, JsValue> | Dot-path lookup over to_json() projection |
to_json | () -> Result<JsValue, JsValue> | Entire JSON projection |
keys | () -> Result<JsValue, JsValue> | Top-level keys |
contains_key | (key: string) -> boolean | Top-level key check |
version / doc_id / replica_id | Accessors | |
serialize / merge | State roundtrip + CRDT join | |
snapshot / restore | Snapshot object roundtrip |
UserPresenceLightweight user-awareness payload object for collaborative UI rendering.
| Method | Signature | Notes |
|---|---|---|
new | (user_id: string, user_name: string, color: string) | Constructor |
set_cursor | (position: number) | Clears selection |
set_selection | (start: number, end: number) | Normalizes range and sets cursor at end |
clear | () -> void | Clears cursor and selection |
user_id / user_name / color | Getters returning strings | |
cursor / selection_start / selection_end | Getters returning optional numbers | |
has_selection | () -> boolean | |
to_json | () -> Result<JsValue, JsValue> | Serialize presence payload |
from_json | (js: JsValue) -> Result<UserPresence, JsValue> | Deserialize payload |
import init, { CollaborativeDocument } from "mdcs-wasm";
await init();
const alice = new CollaborativeDocument("doc-1", "alice");
const bob = new CollaborativeDocument("doc-1", "bob");
alice.insert(0, "Hello");
alice.apply_bold(0, 5);
// transport payload from alice -> bob
const wire = alice.serialize();
if (typeof wire === "string") {
bob.merge(wire);
}
console.log(bob.get_text());
console.log(bob.get_html());
const snapshot = doc.snapshot();
if (snapshot) {
const restored = CollaborativeDocument.restore(snapshot);
}
const json = new JsonDocument("profile-doc", "replica-a");
json.set_object("profile");
json.set_string("profile.name", "Alice");
json.set_array("tags");
json.array_push_string("tags", "crdt");
const remoteState = json.serialize();
peer.merge(remoteState);
const presence = new UserPresence("u1", "Alice", "#FF6B6B");
presence.set_selection(4, 10);
const payload = presence.to_json();
// send payload via your transport, then:
const remotePresence = UserPresence.from_json(payload);
The WASM SDK intentionally does not include peer/network transport. Typical JS/TS flow:
insert, set_*, etc.)serialize()merge(remote_state)version increments for local write operations and on merge. Treat it as a local change counter, not a globally synchronized version clock.
All document types use a snapshot envelope with this shape:
{
doc_id: string;
replica_id: string;
version: number;
state: string; // serialized CRDT JSON string
}
All fallible bindings return Result<_, JsValue> to JS. Common failure classes:
serde_wasm_bindgen)JsonDocumentpath exists but is not an array)Use try/catch around calls such as merge, restore, and JSON setters when consuming from JS/TS.
serialize() docs mention base64, implementation emits JSON string — treat payload as JSON text.array_remove result conversion.generate_replica_id() is convenience-only — timestamp + random bits, not a cryptographic or RFC-UUID guarantee.The crate includes native unit tests for API behavior and convergence patterns. Full browser/WASM integration behavior (especially JS serialization edge cases) should be validated with wasm-bindgen-test in a WASM test target.