Skip to content

Commit 51184f7

Browse files
authored
docs: ephemeral store (#9)
* doc: ephemeral store
1 parent c25facd commit 51184f7

File tree

2 files changed

+97
-0
lines changed

2 files changed

+97
-0
lines changed

pages/docs/tutorial/ephemeral.md

Lines changed: 97 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,97 @@
1+
---
2+
keywords: "ephemeral, awareness, presence, collaborative"
3+
description: "How to use Loro's ephemeral store feature to implement user awareness and online status management in real-time collaboration."
4+
---
5+
6+
# Ephemeral Store
7+
8+
In real-time collaborative scenarios, Presence information is just as important as maintaining document consistency across peers through CRDTs. This includes information such as the current collaborator's username, mouse pointer position, or selected objects. We need a mechanism that doesn't persist in the CRDT Document but remains ephemeral, allowing collaborators to perceive each other's presence for better coordination and to avoid conflicts when multiple users edit the same object. This is why we've introduced the Ephemeral Store.
9+
10+
![](/images/ephemeral.png)
11+
12+
Since Ephemeral information is primarily used for real-time collaboration, we've chosen a simple yet effective approach. The Ephemeral Store is a timestamp-based, last-write-wins key-value store. Each entry maintains its own timestamp of the last update, enabling the system to send only the updated entry content rather than the complete current state.
13+
14+
15+
## Example
16+
17+
```ts
18+
import {
19+
EphemeralStore,
20+
EphemeralListener,
21+
EphemeralStoreEvent,
22+
} from "loro-crdt";
23+
24+
const store = new EphemeralStore();
25+
// Set ephemeral data
26+
store.set("loro-prosemirror", {
27+
anchor: ...,
28+
focus: ...,
29+
user: "Alice"
30+
});
31+
store.set("online-users", ["Alice", "Bob"]);
32+
33+
expect(storeB.get("online-users")).toEqual(["Alice", "Bob"]);
34+
// Encode only the data for `loro-prosemirror`
35+
const encoded = store.encode("loro-prosemirror")
36+
37+
store.subscribe((e: EphemeralStoreEvent) => {
38+
// Listen to changes from `local`, `remote`, or `timeout` events
39+
});
40+
```
41+
42+
## API
43+
44+
- `constructor(timeout)`:
45+
Creates a new EphemeralStore instance with an optional timeout parameter (default: 30000ms). The timeout determines how long ephemeral data remains valid before being automatically removed.
46+
47+
- `set(key, value)`:
48+
Sets a value for the specified key in the ephemeral store. If the key already exists, its value will be updated.
49+
50+
- `get(key)`:
51+
Retrieves the current value for the specified key, or returns `undefined` if the key doesn't exist.
52+
53+
- `delete(key)`:
54+
Removes the specified key and its associated value from the ephemeral store.
55+
56+
- `getAllStates()`:
57+
Returns all current key-value pairs in the ephemeral store.
58+
59+
- `keys()`:
60+
Returns an array of all keys currently in the ephemeral store.
61+
62+
- `encode(key)`:
63+
Encodes the value associated with the specified key into a binary format that can be transmitted to other peers.
64+
65+
- `encodeAll()`:
66+
Encodes all key-value pairs in the ephemeral store into a binary format.
67+
68+
- `apply(bytes)`:
69+
Applies encoded ephemeral data received from other peers to the local ephemeral store.
70+
71+
- `subscribe((event: EphemeralStoreEvent)=>void)`:
72+
Registers a listener function that will be called whenever the ephemeral store is updated, either from local changes, remote changes, or timeout events.
73+
```ts
74+
interface EphemeralStoreEvent {
75+
// The source of the event: local changes, imported from remote, or timeout expiration
76+
by: "local" | "import" | "timeout";
77+
// Array of keys that were newly added
78+
added: string[];
79+
// Array of keys that had their values updated
80+
updated: string[];
81+
// Array of keys that were removed
82+
removed: string[];
83+
}
84+
```
85+
86+
- `subscribeLocalUpdates((bytes: Uint8Array) => void)`:
87+
Registers a listener that will be called only for local updates to the ephemeral store.
88+
```ts
89+
// you need maintain the Subscription to avoid gc
90+
const _sub1 = ephemeral1.subscribeLocalUpdates((update) => {
91+
ephemeral2.apply(update);
92+
});
93+
94+
const _sub2 = ephemeral2.subscribeLocalUpdates((update) => {
95+
ephemeral1.apply(update);
96+
});
97+
```

public/images/ephemeral.png

37.5 KB
Loading

0 commit comments

Comments
 (0)