loro-crdt 1.4.5 → 1.5.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +160 -0
- package/base64/index.d.ts +52 -2
- package/base64/index.js +376 -26
- package/base64/loro_wasm.d.ts +239 -5
- package/base64/loro_wasm_bg-536e230f.js +64 -0
- package/bundler/index.d.ts +52 -2
- package/bundler/index.js +92 -3
- package/bundler/index.js.map +1 -1
- package/bundler/loro_wasm.d.ts +239 -5
- package/bundler/loro_wasm_bg.js +281 -22
- package/bundler/loro_wasm_bg.wasm +0 -0
- package/bundler/loro_wasm_bg.wasm.d.ts +20 -0
- package/nodejs/index.d.ts +52 -2
- package/nodejs/index.js +92 -1
- package/nodejs/index.js.map +1 -1
- package/nodejs/loro_wasm.d.ts +239 -5
- package/nodejs/loro_wasm.js +283 -22
- package/nodejs/loro_wasm_bg.wasm +0 -0
- package/nodejs/loro_wasm_bg.wasm.d.ts +20 -0
- package/package.json +1 -1
- package/web/index.d.ts +52 -2
- package/web/index.js +92 -3
- package/web/index.js.map +1 -1
- package/web/loro_wasm.d.ts +259 -5
- package/web/loro_wasm.js +278 -20
- package/web/loro_wasm_bg.wasm +0 -0
- package/web/loro_wasm_bg.wasm.d.ts +20 -0
- package/base64/loro_wasm_bg-2fc402da.js +0 -64
package/base64/loro_wasm.d.ts
CHANGED
|
@@ -161,6 +161,126 @@ interface LoroDoc {
|
|
|
161
161
|
*/
|
|
162
162
|
subscribeLocalUpdates(f: (bytes: Uint8Array) => void): () => void
|
|
163
163
|
|
|
164
|
+
/**
|
|
165
|
+
* Subscribe to the first commit from a peer. Operations performed on the `LoroDoc` within this callback
|
|
166
|
+
* will be merged into the current commit.
|
|
167
|
+
*
|
|
168
|
+
* This is useful for managing the relationship between `PeerID` and user information.
|
|
169
|
+
* For example, you could store user names in a `LoroMap` using `PeerID` as the key and the `UserID` as the value.
|
|
170
|
+
*
|
|
171
|
+
* @param f - A callback function that receives a peer id.
|
|
172
|
+
*
|
|
173
|
+
* @example
|
|
174
|
+
* ```ts
|
|
175
|
+
* const doc = new LoroDoc();
|
|
176
|
+
* doc.setPeerId(0);
|
|
177
|
+
* const p = [];
|
|
178
|
+
* doc.subscribeFirstCommitFromPeer((peer) => {
|
|
179
|
+
* p.push(peer);
|
|
180
|
+
* doc.getMap("map").set(e.peer, "user-" + e.peer);
|
|
181
|
+
* });
|
|
182
|
+
* doc.getList("list").insert(0, 100);
|
|
183
|
+
* doc.commit();
|
|
184
|
+
* doc.getList("list").insert(0, 200);
|
|
185
|
+
* doc.commit();
|
|
186
|
+
* doc.setPeerId(1);
|
|
187
|
+
* doc.getList("list").insert(0, 300);
|
|
188
|
+
* doc.commit();
|
|
189
|
+
* expect(p).toEqual(["0", "1"]);
|
|
190
|
+
* expect(doc.getMap("map").get("0")).toBe("user-0");
|
|
191
|
+
* ```
|
|
192
|
+
**/
|
|
193
|
+
subscribeFirstCommitFromPeer(f: (e: { peer: PeerID }) => void): () => void
|
|
194
|
+
|
|
195
|
+
/**
|
|
196
|
+
* Subscribe to the pre-commit event.
|
|
197
|
+
*
|
|
198
|
+
* The callback will be called when the changes are committed but not yet applied to the OpLog.
|
|
199
|
+
* You can modify the commit message and timestamp in the callback by `ChangeModifier`.
|
|
200
|
+
*
|
|
201
|
+
* @example
|
|
202
|
+
* ```ts
|
|
203
|
+
* const doc = new LoroDoc();
|
|
204
|
+
* doc.subscribePreCommit((e) => {
|
|
205
|
+
* e.modifier.setMessage("test").setTimestamp(Date.now());
|
|
206
|
+
* });
|
|
207
|
+
* doc.getList("list").insert(0, 100);
|
|
208
|
+
* doc.commit();
|
|
209
|
+
* expect(doc.getChangeAt({ peer: "0", counter: 0 }).message).toBe("test");
|
|
210
|
+
* ```
|
|
211
|
+
*
|
|
212
|
+
* ### Advanced Example: Creating a Merkle DAG
|
|
213
|
+
*
|
|
214
|
+
* By combining `doc.subscribePreCommit` with `doc.exportJsonInIdSpan`, you can implement advanced features like representing Loro's editing history as a Merkle DAG:
|
|
215
|
+
*
|
|
216
|
+
* ```ts
|
|
217
|
+
* const doc = new LoroDoc();
|
|
218
|
+
* doc.setPeerId(0);
|
|
219
|
+
* doc.subscribePreCommit((e) => {
|
|
220
|
+
* const changes = doc.exportJsonInIdSpan(e.changeMeta)
|
|
221
|
+
* expect(changes).toHaveLength(1);
|
|
222
|
+
* const hash = crypto.createHash('sha256');
|
|
223
|
+
* const change = {
|
|
224
|
+
* ...changes[0],
|
|
225
|
+
* deps: changes[0].deps.map(d => {
|
|
226
|
+
* const depChange = doc.getChangeAt(idStrToId(d))
|
|
227
|
+
* return depChange.message;
|
|
228
|
+
* })
|
|
229
|
+
* }
|
|
230
|
+
* console.log(change); // The output is shown below
|
|
231
|
+
* hash.update(JSON.stringify(change));
|
|
232
|
+
* const sha256Hash = hash.digest('hex');
|
|
233
|
+
* e.modifier.setMessage(sha256Hash);
|
|
234
|
+
* });
|
|
235
|
+
*
|
|
236
|
+
* doc.getList("list").insert(0, 100);
|
|
237
|
+
* doc.commit();
|
|
238
|
+
* // Change 0
|
|
239
|
+
* // {
|
|
240
|
+
* // id: '0@0',
|
|
241
|
+
* // timestamp: 0,
|
|
242
|
+
* // deps: [],
|
|
243
|
+
* // lamport: 0,
|
|
244
|
+
* // msg: undefined,
|
|
245
|
+
* // ops: [
|
|
246
|
+
* // {
|
|
247
|
+
* // container: 'cid:root-list:List',
|
|
248
|
+
* // content: { type: 'insert', pos: 0, value: [100] },
|
|
249
|
+
* // counter: 0
|
|
250
|
+
* // }
|
|
251
|
+
* // ]
|
|
252
|
+
* // }
|
|
253
|
+
*
|
|
254
|
+
*
|
|
255
|
+
* doc.getList("list").insert(0, 200);
|
|
256
|
+
* doc.commit();
|
|
257
|
+
* // Change 1
|
|
258
|
+
* // {
|
|
259
|
+
* // id: '1@0',
|
|
260
|
+
* // timestamp: 0,
|
|
261
|
+
* // deps: [
|
|
262
|
+
* // '2af99cf93869173984bcf6b1ce5412610b0413d027a5511a8f720a02a4432853'
|
|
263
|
+
* // ],
|
|
264
|
+
* // lamport: 1,
|
|
265
|
+
* // msg: undefined,
|
|
266
|
+
* // ops: [
|
|
267
|
+
* // {
|
|
268
|
+
* // container: 'cid:root-list:List',
|
|
269
|
+
* // content: { type: 'insert', pos: 0, value: [200] },
|
|
270
|
+
* // counter: 1
|
|
271
|
+
* // }
|
|
272
|
+
* // ]
|
|
273
|
+
* // }
|
|
274
|
+
*
|
|
275
|
+
* expect(doc.getChangeAt({ peer: "0", counter: 0 }).message).toBe("2af99cf93869173984bcf6b1ce5412610b0413d027a5511a8f720a02a4432853");
|
|
276
|
+
* expect(doc.getChangeAt({ peer: "0", counter: 1 }).message).toBe("aedbb442c554ecf59090e0e8339df1d8febf647f25cc37c67be0c6e27071d37f");
|
|
277
|
+
* ```
|
|
278
|
+
*
|
|
279
|
+
* @param f - A callback function that receives a pre commit event.
|
|
280
|
+
*
|
|
281
|
+
**/
|
|
282
|
+
subscribePreCommit(f: (e: { changeMeta: Change, origin: string, modifier: ChangeModifier }) => void): () => void
|
|
283
|
+
|
|
164
284
|
/**
|
|
165
285
|
* Convert the document to a JSON value with a custom replacer function.
|
|
166
286
|
*
|
|
@@ -759,7 +879,6 @@ export type AwarenessListener = (
|
|
|
759
879
|
origin: "local" | "timeout" | "remote" | string,
|
|
760
880
|
) => void;
|
|
761
881
|
|
|
762
|
-
|
|
763
882
|
interface Listener {
|
|
764
883
|
(event: LoroEventBatch): void;
|
|
765
884
|
}
|
|
@@ -856,10 +975,15 @@ interface LoroDoc<T extends Record<string, Container> = Record<string, Container
|
|
|
856
975
|
*/
|
|
857
976
|
exportJsonUpdates(start?: VersionVector, end?: VersionVector, withPeerCompression?: boolean): JsonSchema;
|
|
858
977
|
/**
|
|
859
|
-
*
|
|
978
|
+
* Exports changes within the specified ID span to JSON schema format.
|
|
860
979
|
*
|
|
861
|
-
* The
|
|
980
|
+
* The JSON schema format produced by this method is identical to the one generated by `export_json_updates`.
|
|
981
|
+
* It ensures deterministic output, making it ideal for hash calculations and integrity checks.
|
|
862
982
|
*
|
|
983
|
+
* This method can also export pending changes from the uncommitted transaction that have not yet been applied to the OpLog.
|
|
984
|
+
*
|
|
985
|
+
* This method will NOT trigger a new commit implicitly.
|
|
986
|
+
*
|
|
863
987
|
* @param idSpan - The id span to export.
|
|
864
988
|
* @returns The changes in the given id span.
|
|
865
989
|
*/
|
|
@@ -1274,6 +1398,25 @@ interface AwarenessWasm<T extends Value = Value> {
|
|
|
1274
1398
|
removeOutdated(): PeerID[];
|
|
1275
1399
|
}
|
|
1276
1400
|
|
|
1401
|
+
type EphemeralListener = (event: EphemeralStoreEvent) => void;
|
|
1402
|
+
type EphemeralLocalListener = (bytes: Uint8Array) => void;
|
|
1403
|
+
|
|
1404
|
+
interface EphemeralStoreWasm<T extends Value = Value> {
|
|
1405
|
+
set(key: string, value: T): void;
|
|
1406
|
+
get(key: string): T | undefined;
|
|
1407
|
+
getAllStates(): Record<string, T>;
|
|
1408
|
+
removeOutdated();
|
|
1409
|
+
subscribeLocalUpdates(f: EphemeralLocalListener): () => void;
|
|
1410
|
+
subscribe(f: EphemeralListener): () => void;
|
|
1411
|
+
}
|
|
1412
|
+
|
|
1413
|
+
interface EphemeralStoreEvent {
|
|
1414
|
+
by: "local" | "import" | "timeout";
|
|
1415
|
+
added: string[];
|
|
1416
|
+
updated: string[];
|
|
1417
|
+
removed: string[];
|
|
1418
|
+
}
|
|
1419
|
+
|
|
1277
1420
|
|
|
1278
1421
|
|
|
1279
1422
|
/**
|
|
@@ -1349,6 +1492,21 @@ export class AwarenessWasm {
|
|
|
1349
1492
|
peers(): (PeerID)[];
|
|
1350
1493
|
}
|
|
1351
1494
|
/**
|
|
1495
|
+
*/
|
|
1496
|
+
export class ChangeModifier {
|
|
1497
|
+
free(): void;
|
|
1498
|
+
/**
|
|
1499
|
+
* @param {string} message
|
|
1500
|
+
* @returns {ChangeModifier}
|
|
1501
|
+
*/
|
|
1502
|
+
setMessage(message: string): ChangeModifier;
|
|
1503
|
+
/**
|
|
1504
|
+
* @param {number} timestamp
|
|
1505
|
+
* @returns {ChangeModifier}
|
|
1506
|
+
*/
|
|
1507
|
+
setTimestamp(timestamp: number): ChangeModifier;
|
|
1508
|
+
}
|
|
1509
|
+
/**
|
|
1352
1510
|
* Cursor is a stable position representation in the doc.
|
|
1353
1511
|
* When expressing the position of a cursor, using "index" can be unstable
|
|
1354
1512
|
* because the cursor's position may change due to other deletions and insertions,
|
|
@@ -1418,6 +1576,63 @@ export class Cursor {
|
|
|
1418
1576
|
kind(): any;
|
|
1419
1577
|
}
|
|
1420
1578
|
/**
|
|
1579
|
+
*/
|
|
1580
|
+
export class EphemeralStoreWasm {
|
|
1581
|
+
free(): void;
|
|
1582
|
+
/**
|
|
1583
|
+
* Creates a new `EphemeralStore` instance.
|
|
1584
|
+
*
|
|
1585
|
+
* The `timeout` parameter specifies the duration in milliseconds.
|
|
1586
|
+
* A state of a peer is considered outdated, if the last update of the state of the peer
|
|
1587
|
+
* is older than the `timeout`.
|
|
1588
|
+
* @param {number} timeout
|
|
1589
|
+
*/
|
|
1590
|
+
constructor(timeout: number);
|
|
1591
|
+
/**
|
|
1592
|
+
* @param {string} key
|
|
1593
|
+
* @param {any} value
|
|
1594
|
+
*/
|
|
1595
|
+
set(key: string, value: any): void;
|
|
1596
|
+
/**
|
|
1597
|
+
* @param {string} key
|
|
1598
|
+
*/
|
|
1599
|
+
delete(key: string): void;
|
|
1600
|
+
/**
|
|
1601
|
+
* @param {string} key
|
|
1602
|
+
* @returns {any}
|
|
1603
|
+
*/
|
|
1604
|
+
get(key: string): any;
|
|
1605
|
+
/**
|
|
1606
|
+
* @returns {any}
|
|
1607
|
+
*/
|
|
1608
|
+
getAllStates(): any;
|
|
1609
|
+
/**
|
|
1610
|
+
* @param {string} key
|
|
1611
|
+
* @returns {Uint8Array}
|
|
1612
|
+
*/
|
|
1613
|
+
encode(key: string): Uint8Array;
|
|
1614
|
+
/**
|
|
1615
|
+
* @returns {Uint8Array}
|
|
1616
|
+
*/
|
|
1617
|
+
encodeAll(): Uint8Array;
|
|
1618
|
+
/**
|
|
1619
|
+
* @param {Uint8Array} data
|
|
1620
|
+
*/
|
|
1621
|
+
apply(data: Uint8Array): void;
|
|
1622
|
+
/**
|
|
1623
|
+
*/
|
|
1624
|
+
removeOutdated(): void;
|
|
1625
|
+
/**
|
|
1626
|
+
* If the state is empty.
|
|
1627
|
+
* @returns {boolean}
|
|
1628
|
+
*/
|
|
1629
|
+
isEmpty(): boolean;
|
|
1630
|
+
/**
|
|
1631
|
+
* @returns {(string)[]}
|
|
1632
|
+
*/
|
|
1633
|
+
keys(): (string)[];
|
|
1634
|
+
}
|
|
1635
|
+
/**
|
|
1421
1636
|
* The handler of a counter container.
|
|
1422
1637
|
*/
|
|
1423
1638
|
export class LoroCounter {
|
|
@@ -2443,6 +2658,27 @@ export class LoroDoc {
|
|
|
2443
2658
|
*/
|
|
2444
2659
|
applyDiff(diff: [ContainerID, Diff|JsonDiff][]): void;
|
|
2445
2660
|
/**
|
|
2661
|
+
* Get the pending operations from the current transaction in JSON format
|
|
2662
|
+
*
|
|
2663
|
+
* This method returns a JSON representation of operations that have been applied
|
|
2664
|
+
* but not yet committed in the current transaction.
|
|
2665
|
+
*
|
|
2666
|
+
* It will use the same data format as `doc.exportJsonUpdates()`
|
|
2667
|
+
*
|
|
2668
|
+
* @example
|
|
2669
|
+
* ```ts
|
|
2670
|
+
* const doc = new LoroDoc();
|
|
2671
|
+
* const text = doc.getText("text");
|
|
2672
|
+
* text.insert(0, "Hello");
|
|
2673
|
+
* // Get pending ops before commit
|
|
2674
|
+
* const pendingOps = doc.getPendingOpsFromCurrentTxnAsJson();
|
|
2675
|
+
* doc.commit();
|
|
2676
|
+
* const emptyOps = doc.getPendingOpsFromCurrentTxnAsJson(); // this is undefined
|
|
2677
|
+
* ```
|
|
2678
|
+
* @returns {JsonSchema | undefined}
|
|
2679
|
+
*/
|
|
2680
|
+
getUncommittedOpsAsJson(): JsonSchema | undefined;
|
|
2681
|
+
/**
|
|
2446
2682
|
* Peer ID of the current writer.
|
|
2447
2683
|
*/
|
|
2448
2684
|
readonly peerId: bigint;
|
|
@@ -3104,8 +3340,6 @@ export class LoroText {
|
|
|
3104
3340
|
*
|
|
3105
3341
|
* You can use it to create a highlight, make a range of text bold, or add a link to a range of text.
|
|
3106
3342
|
*
|
|
3107
|
-
* Note: this is not suitable for unmergeable annotations like comments.
|
|
3108
|
-
*
|
|
3109
3343
|
* @example
|
|
3110
3344
|
* ```ts
|
|
3111
3345
|
* import { LoroDoc } from "loro-crdt";
|