Skip to content

Commit fe335c2

Browse files
committed
docs: v1.5.0 changelog
1 parent f65e1ac commit fe335c2

File tree

1 file changed

+113
-0
lines changed

1 file changed

+113
-0
lines changed

pages/changelog/v1.5.0.mdx

Lines changed: 113 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,113 @@
1+
---
2+
version: "v1.5.0"
3+
title: "release v1.5.0"
4+
date: 2025/04/04
5+
---
6+
7+
## New
8+
9+
### 1. New Hooks
10+
11+
`doc.subscribePreCommit(listener)` - Modify commit options before processing:
12+
13+
This hook is particularly useful because doc.commit() is often invoked implicitly in various methods such as doc.import, doc.export, doc.checkout, and doc.exportJsonUpdates. Without this hook, users attempting to add custom messages to each commit might miss these implicit commit triggers.
14+
15+
```ts
16+
const doc = new LoroDoc();
17+
doc.setPeerId(0);
18+
doc.subscribePreCommit((e) => {
19+
e.modifier.setMessage("test").setTimestamp(Date.now());
20+
});
21+
doc.getList("list").insert(0, 100);
22+
doc.commit();
23+
expect(doc.getChangeAt({ peer: "0", counter: 0 }).message).toBe("test");
24+
```
25+
26+
Advanced Example - Creating a Merkle DAG:
27+
28+
```ts
29+
const doc = new LoroDoc();
30+
doc.setPeerId(0);
31+
doc.subscribePreCommit((e) => {
32+
const changes = doc.exportJsonInIdSpan(e.changeMeta);
33+
expect(changes).toHaveLength(1);
34+
const hash = crypto.createHash("sha256");
35+
const change = {
36+
...changes[0],
37+
deps: changes[0].deps.map((d) => {
38+
const depChange = doc.getChangeAt(idStrToId(d));
39+
return depChange.message;
40+
}),
41+
};
42+
hash.update(JSON.stringify(change));
43+
const sha256Hash = hash.digest("hex");
44+
e.modifier.setMessage(sha256Hash);
45+
});
46+
47+
doc.getList("list").insert(0, 100);
48+
doc.commit();
49+
50+
expect(doc.getChangeAt({ peer: "0", counter: 0 }).message).toBe(
51+
"2af99cf93869173984bcf6b1ce5412610b0413d027a5511a8f720a02a4432853",
52+
);
53+
```
54+
55+
`doc.subscribeFirstCommitFromPeer(listener)` - Triggers on first peer interaction:
56+
57+
This hook provides an ideal point to associate peer information (such as author identity) with the document.
58+
59+
```ts
60+
const doc = new LoroDoc();
61+
doc.setPeerId(0);
62+
doc.subscribeFirstCommitFromPeer((e) => {
63+
doc.getMap("users").set(e.peer, "user-" + e.peer);
64+
});
65+
doc.getList("list").insert(0, 100);
66+
doc.commit();
67+
expect(doc.getMap("users").get("0")).toBe("user-0");
68+
```
69+
70+
### 2. EphemeralStore
71+
72+
EphemeralStore is a better alternative to Awareness for ephemeral states:
73+
74+
Awareness is commonly used as a state-based CRDT for handling ephemeral states in real-time collaboration scenarios, such as cursor positions and application component highlights. As application complexity grows, Awareness may be set in multiple places, from cursor positions to user presence. However, the current version of Awareness doesn't support partial state updates, which means even minor mouse movements require synchronizing the entire Awareness state.
75+
76+
```ts
77+
awareness.setLocalState({
78+
...awareness.getLocalState(),
79+
x: 167,
80+
});
81+
```
82+
Since Awareness is primarily used in real-time collaboration scenarios where consistency requirements are relatively low, we can make it more flexible. We've introduced EphemeralStore as an alternative to Awareness. Think of it as a simple key-value store that uses timestamp-based last-write-wins for conflict resolution. You can choose the appropriate granularity for your key-value pairs based on your application's needs, and only modified key-value pairs are synchronized.
83+
84+
85+
```ts
86+
import {
87+
EphemeralStore,
88+
EphemeralListener,
89+
EphemeralStoreEvent,
90+
} from "loro-crdt";
91+
92+
const store = new EphemeralStore();
93+
// Set ephemeral data
94+
store.set("loro-prosemirror", {
95+
anchor: ...,
96+
focus: ...,
97+
user: "Alice"
98+
});
99+
store.set("online-users", ["Alice", "Bob"]);
100+
101+
expect(storeB.get("online-users")).toEqual(["Alice", "Bob"]);
102+
// Encode only the data for `loro-prosemirror`
103+
const encoded = store.encode("loro-prosemirror")
104+
105+
store.subscribe((e: EphemeralStoreEvent) => {
106+
// Listen to changes from `local`, `remote`, or `timeout` events
107+
});
108+
```
109+
110+
## Fix
111+
112+
- Fixed text styling at end "\n" character
113+
- Added JSON support for current transaction operations

0 commit comments

Comments
 (0)