IrohEx.Automerge (iroh_ex v0.0.15)
High-level API for automerge CRDT documents.
Automerge is a JSON-like data structure (a CRDT) that can be modified concurrently by different users, and merged again automatically.
Features
- Maps: Nested key-value structures
- Lists: Ordered sequences with concurrent insert support
- Text: Collaborative text editing with character-level merging
- Counters: Distributed counters that always converge correctly
Basic Usage
# Create a node first
node = IrohEx.Native.create_node(self(), IrohEx.NodeConfig.build())
# Create a document
doc_id = IrohEx.Automerge.new(node)
# Put some data
:ok = IrohEx.Automerge.put(node, doc_id, [], "name", "Alice")
:ok = IrohEx.Automerge.put(node, doc_id, [], "age", 30)
# Create nested structures
IrohEx.Automerge.create_map(node, doc_id, [], "profile")
:ok = IrohEx.Automerge.put(node, doc_id, ["profile"], "email", "alice@example.com")
# Read data
"Alice" = IrohEx.Automerge.get(node, doc_id, [], "name")Merging Documents
# Fork a document to simulate concurrent edits
doc2 = IrohEx.Automerge.fork(node, doc_id)
# Make changes to both
:ok = IrohEx.Automerge.put(node, doc_id, [], "field_a", "value_a")
:ok = IrohEx.Automerge.put(node, doc2, [], "field_b", "value_b")
# Merge doc2 into doc_id
{:ok, bytes} = IrohEx.Automerge.save(node, doc2)
:ok = IrohEx.Automerge.merge(node, doc_id, bytes)
# Now doc_id has both changes!
Summary
Functions
Get the current counter value.
Increment a counter (creates it if it doesn't exist).
Create a list at the given path.
Create a nested map structure.
Create a collaborative text object.
Delete a document from memory.
Delete a key from a map.
Fork a document (create a copy with shared history).
Get a value at a nested path.
Get all keys from a map.
List all document IDs.
Delete a value from a list by index.
Get a value from a list by index.
Insert a value at a specific index.
Get the length of a list.
Push a value to the end of a list.
Load a document from binary data.
Merge another document's changes into this one.
Create a new empty automerge document.
Put a value at a nested path.
Save a document to binary format.
Sync document with all connected peers via gossip.
Delete text at a position.
Get the full text content.
Insert text at a position.
Get document as JSON string for debugging.
Types
Functions
Get the current counter value.
Examples
42 = IrohEx.Automerge.counter_get(node, doc_id, [], "views")
Increment a counter (creates it if it doesn't exist).
Counters are a special CRDT type that always converge correctly, even with concurrent increments from multiple nodes.
Examples
1 = IrohEx.Automerge.counter_increment(node, doc_id, [], "views", 1)
6 = IrohEx.Automerge.counter_increment(node, doc_id, [], "views", 5)
4 = IrohEx.Automerge.counter_increment(node, doc_id, [], "views", -2)
Create a list at the given path.
Examples
IrohEx.Automerge.create_list(node, doc_id, [], "items")
Create a nested map structure.
Examples
IrohEx.Automerge.create_map(node, doc_id, [], "users")
IrohEx.Automerge.create_map(node, doc_id, ["users"], "alice")
:ok = IrohEx.Automerge.put(node, doc_id, ["users", "alice"], "name", "Alice")
@spec create_text(node_ref(), doc_id(), path(), binary(), binary()) :: {:ok, binary()} | {:error, term()}
Create a collaborative text object.
Text objects support character-level concurrent editing with automatic conflict resolution.
Examples
IrohEx.Automerge.create_text(node, doc_id, [], "content", "Hello World")
Delete a document from memory.
Examples
true = IrohEx.Automerge.delete(node, doc_id)
Delete a key from a map.
Examples
:ok = IrohEx.Automerge.delete_key(node, doc_id, [], "old_field")
Fork a document (create a copy with shared history).
Forking is useful for:
- Simulating concurrent edits in tests
- Creating branches of a document
- Offline editing that will be merged later
Examples
doc2 = IrohEx.Automerge.fork(node, doc_id)
Get a value at a nested path.
Examples
"Alice" = IrohEx.Automerge.get(node, doc_id, [], "name")
:not_found = IrohEx.Automerge.get(node, doc_id, [], "nonexistent")
Get all keys from a map.
Examples
["name", "age", "email"] = IrohEx.Automerge.keys(node, doc_id, [])
List all document IDs.
Examples
doc_ids = IrohEx.Automerge.list(node)
@spec list_delete(node_ref(), doc_id(), path(), non_neg_integer()) :: :ok | {:error, term()}
Delete a value from a list by index.
Examples
:ok = IrohEx.Automerge.list_delete(node, doc_id, ["items"], 0)
@spec list_get(node_ref(), doc_id(), path(), non_neg_integer()) :: term()
Get a value from a list by index.
Examples
"first" = IrohEx.Automerge.list_get(node, doc_id, ["items"], 0)
@spec list_insert(node_ref(), doc_id(), path(), non_neg_integer(), term()) :: :ok | {:error, term()}
Insert a value at a specific index.
Examples
:ok = IrohEx.Automerge.list_insert(node, doc_id, ["items"], 0, "at_beginning")
@spec list_length(node_ref(), doc_id(), path()) :: non_neg_integer()
Get the length of a list.
Examples
3 = IrohEx.Automerge.list_length(node, doc_id, ["items"])
Push a value to the end of a list.
Examples
IrohEx.Automerge.create_list(node, doc_id, [], "items")
:ok = IrohEx.Automerge.list_push(node, doc_id, ["items"], "first")
:ok = IrohEx.Automerge.list_push(node, doc_id, ["items"], "second")
Load a document from binary data.
Examples
{:ok, doc_id} = IrohEx.Automerge.load(node, saved_bytes)
Merge another document's changes into this one.
Examples
{:ok, other_bytes} = IrohEx.Automerge.save(node, other_doc_id)
:ok = IrohEx.Automerge.merge(node, doc_id, other_bytes)
Create a new empty automerge document.
Examples
doc_id = IrohEx.Automerge.new(node)
Put a value at a nested path.
Parameters
node- The node referencedoc_id- The document IDpath- List of keys to navigate to (empty for root)key- The key to setvalue- The value (string, integer, float, boolean, or binary)
Examples
# Set at root level
:ok = IrohEx.Automerge.put(node, doc_id, [], "name", "Alice")
# Set at nested path (path must exist)
:ok = IrohEx.Automerge.put(node, doc_id, ["users", "alice"], "email", "alice@example.com")
Save a document to binary format.
The binary format is compact and can be stored or transmitted.
Examples
{:ok, bytes} = IrohEx.Automerge.save(node, doc_id)
File.write!("document.automerge", bytes)
Sync document with all connected peers via gossip.
This broadcasts the full document to all peers in the gossip network.
Examples
:ok = IrohEx.Automerge.sync(node, doc_id)
@spec text_delete(node_ref(), doc_id(), path(), non_neg_integer(), non_neg_integer()) :: :ok | {:error, term()}
Delete text at a position.
Examples
:ok = IrohEx.Automerge.text_delete(node, doc_id, ["content"], 5, 10)
# Deletes 10 characters starting at position 5
Get the full text content.
Examples
"Hello World" = IrohEx.Automerge.text_get(node, doc_id, ["content"])
@spec text_insert(node_ref(), doc_id(), path(), non_neg_integer(), binary()) :: :ok | {:error, term()}
Insert text at a position.
Examples
:ok = IrohEx.Automerge.text_insert(node, doc_id, ["content"], 5, " Beautiful")
# "Hello Beautiful World"
Get document as JSON string for debugging.
Examples
json = IrohEx.Automerge.to_json(node, doc_id)
IO.puts(json)