loro-crdt 1.0.8 → 1.1.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 CHANGED
@@ -1,5 +1,30 @@
1
1
  # Changelog
2
2
 
3
+ ## 1.1.0
4
+
5
+ ### Minor Changes
6
+
7
+ - 6e878d2: Feat add API to query creators, the last editors/movers
8
+ - 778ca54: Feat: allow users to query the changed containers in the target id range
9
+
10
+ ### Patch Changes
11
+
12
+ - 6616101: Perf: optimize importBatch
13
+
14
+ When using importBatch to import a series of snapshots and updates, we should import the snapshot with the greatest version first.
15
+
16
+ - 6e878d2: Feat: getLastEditor on LoroMap
17
+ - 8486234: Fix get encoded blob meta
18
+
19
+ ## 1.0.9
20
+
21
+ ### Patch Changes
22
+
23
+ - 7bf6db7: Add `push` to LoroText and `pushContainer` to LoroList LoroMovableList
24
+ - 9b60d01: Define the behavior of `doc.fork()` when the doc is detached
25
+
26
+ It will fork at the current state_frontiers, which is equivalent to calling `doc.fork_at(&doc.state_frontiers())`
27
+
3
28
  ## 1.0.8
4
29
 
5
30
  ### Patch Changes
@@ -26,12 +26,13 @@ export function setDebug(): void;
26
26
  * - endVersionVector
27
27
  * - startTimestamp
28
28
  * - endTimestamp
29
- * - isSnapshot
29
+ * - mode
30
30
  * - changeNum
31
31
  * @param {Uint8Array} blob
32
+ * @param {boolean} check_checksum
32
33
  * @returns {ImportBlobMetadata}
33
34
  */
34
- export function decodeImportBlobMeta(blob: Uint8Array): ImportBlobMetadata;
35
+ export function decodeImportBlobMeta(blob: Uint8Array, check_checksum: boolean): ImportBlobMetadata;
35
36
 
36
37
  /**
37
38
  * Container types supported by loro.
@@ -262,7 +263,7 @@ export interface ImportBlobMetadata {
262
263
  startFrontiers: OpId[],
263
264
  startTimestamp: number;
264
265
  endTimestamp: number;
265
- isSnapshot: boolean;
266
+ mode: "outdated-snapshot" | "outdated-update" | "snapshot" | "shallow-snapshot" | "update";
266
267
  changeNum: number;
267
268
  }
268
269
 
@@ -351,6 +352,11 @@ export type TreeNodeValue = {
351
352
  children: TreeNodeValue[],
352
353
  }
353
354
 
355
+ export type TreeNodeJSON<T> = Omit<TreeNodeValue, 'meta' | 'children'> & {
356
+ meta: T,
357
+ children: TreeNodeJSON<T>[],
358
+ }
359
+
354
360
  interface LoroTree{
355
361
  toArray(): TreeNodeValue[];
356
362
  getNodes(options?: { withDeleted: boolean = false }): LoroTreeNode[];
@@ -432,6 +438,11 @@ export type JsonChange = {
432
438
  ops: JsonOp[]
433
439
  }
434
440
 
441
+ export interface TextUpdateOptions {
442
+ timeoutMs?: number,
443
+ useRefinedDiff?: boolean,
444
+ }
445
+
435
446
  export type ExportMode = {
436
447
  mode: "update",
437
448
  from?: VersionVector,
@@ -779,6 +790,10 @@ interface LoroList<T = unknown> {
779
790
  * ```
780
791
  */
781
792
  insertContainer<C extends Container>(pos: number, child: C): T extends C ? T : C;
793
+ /**
794
+ * Push a container to the end of the list.
795
+ */
796
+ pushContainer<C extends Container>(child: C): T extends C ? T : C;
782
797
  /**
783
798
  * Get the value at the index. If the value is a container, the corresponding handler will be returned.
784
799
  *
@@ -851,6 +866,10 @@ interface LoroMovableList<T = unknown> {
851
866
  * ```
852
867
  */
853
868
  insertContainer<C extends Container>(pos: number, child: C): T extends C ? T : C;
869
+ /**
870
+ * Push a container to the end of the list.
871
+ */
872
+ pushContainer<C extends Container>(child: C): T extends C ? T : C;
854
873
  /**
855
874
  * Get the value at the index. If the value is a container, the corresponding handler will be returned.
856
875
  *
@@ -1004,6 +1023,32 @@ interface LoroText {
1004
1023
  insert(pos: number, text: string): void;
1005
1024
  delete(pos: number, len: number): void;
1006
1025
  subscribe(listener: Listener): Subscription;
1026
+ /**
1027
+ * Update the current text to the target text.
1028
+ *
1029
+ * It will calculate the minimal difference and apply it to the current text.
1030
+ * It uses Myers' diff algorithm to compute the optimal difference.
1031
+ *
1032
+ * This could take a long time for large texts (e.g. > 50_000 characters).
1033
+ * In that case, you should use `updateByLine` instead.
1034
+ *
1035
+ * @example
1036
+ * ```ts
1037
+ * import { LoroDoc } from "loro-crdt";
1038
+ *
1039
+ * const doc = new LoroDoc();
1040
+ * const text = doc.getText("text");
1041
+ * text.insert(0, "Hello");
1042
+ * text.update("Hello World");
1043
+ * console.log(text.toString()); // "Hello World"
1044
+ * ```
1045
+ */
1046
+ update(text: string, options?: TextUpdateOptions): void;
1047
+ /**
1048
+ * Update the current text based on the provided text.
1049
+ * This update calculation is line-based, which will be more efficient but less precise.
1050
+ */
1051
+ updateByLine(text: string, options?: TextUpdateOptions): void;
1007
1052
  }
1008
1053
  interface LoroTree<T extends Record<string, unknown> = Record<string, unknown>> {
1009
1054
  new(): LoroTree<T>;
@@ -1072,6 +1117,7 @@ interface LoroTreeNode<T extends Record<string, unknown> = Record<string, unknow
1072
1117
  * the WASM boundary.
1073
1118
  */
1074
1119
  children(): Array<LoroTreeNode<T>> | undefined;
1120
+ toJSON(): TreeNodeJSON<T>;
1075
1121
  }
1076
1122
  interface AwarenessWasm<T extends Value = Value> {
1077
1123
  getState(peer: PeerID): T | undefined;
@@ -1479,11 +1525,16 @@ export class LoroDoc {
1479
1525
  * Duplicate the document with a different PeerID
1480
1526
  *
1481
1527
  * The time complexity and space complexity of this operation are both O(n),
1528
+ *
1529
+ * When called in detached mode, it will fork at the current state frontiers.
1530
+ * It will have the same effect as `forkAt(&self.frontiers())`.
1482
1531
  * @returns {LoroDoc}
1483
1532
  */
1484
1533
  fork(): LoroDoc;
1485
1534
  /**
1486
1535
  * Creates a new LoroDoc at a specified version (Frontiers)
1536
+ *
1537
+ * The created doc will only contain the history before the specified frontiers.
1487
1538
  * @param {({ peer: PeerID, counter: number })[]} frontiers
1488
1539
  * @returns {LoroDoc}
1489
1540
  */
@@ -1519,9 +1570,9 @@ export class LoroDoc {
1519
1570
  * @param ids - the changes to visit
1520
1571
  * @param f - the callback function, return `true` to continue visiting, return `false` to stop
1521
1572
  * @param {({ peer: PeerID, counter: number })[]} ids
1522
- * @param {Function} f
1573
+ * @param {(change: ChangeMeta) => boolean} f
1523
1574
  */
1524
- travelChangeAncestors(ids: ({ peer: PeerID, counter: number })[], f: Function): void;
1575
+ travelChangeAncestors(ids: ({ peer: PeerID, counter: number })[], f: (change: ChangeMeta) => boolean): void;
1525
1576
  /**
1526
1577
  * Checkout the `DocState` to a specific version.
1527
1578
  *
@@ -1997,6 +2048,23 @@ export class LoroDoc {
1997
2048
  */
1998
2049
  getCursorPos(cursor: Cursor): { update?: Cursor, offset: number, side: Side };
1999
2050
  /**
2051
+ * Gets container IDs modified in the given ID range.
2052
+ *
2053
+ * **NOTE:** This method will implicitly commit.
2054
+ *
2055
+ * This method identifies which containers were affected by changes in a given range of operations.
2056
+ * It can be used together with `doc.travelChangeAncestors()` to analyze the history of changes
2057
+ * and determine which containers were modified by each change.
2058
+ *
2059
+ * @param id - The starting ID of the change range
2060
+ * @param len - The length of the change range to check
2061
+ * @returns An array of container IDs that were modified in the given range
2062
+ * @param {{ peer: PeerID, counter: number }} id
2063
+ * @param {number} len
2064
+ * @returns {(ContainerID)[]}
2065
+ */
2066
+ getChangedContainersIn(id: { peer: PeerID, counter: number }, len: number): (ContainerID)[];
2067
+ /**
2000
2068
  * Peer ID of the current writer.
2001
2069
  */
2002
2070
  readonly peerId: bigint;
@@ -2092,6 +2160,11 @@ export class LoroList {
2092
2160
  */
2093
2161
  clear(): void;
2094
2162
  /**
2163
+ * @param {number} pos
2164
+ * @returns {{ peer: PeerID, counter: number } | undefined}
2165
+ */
2166
+ getIdAt(pos: number): { peer: PeerID, counter: number } | undefined;
2167
+ /**
2095
2168
  * Get the id of this container.
2096
2169
  */
2097
2170
  readonly id: ContainerID;
@@ -2242,6 +2315,12 @@ export class LoroMap {
2242
2315
  */
2243
2316
  clear(): void;
2244
2317
  /**
2318
+ * Get the peer id of the last editor on the given entry
2319
+ * @param {string} key
2320
+ * @returns {PeerID | undefined}
2321
+ */
2322
+ getLastEditor(key: string): PeerID | undefined;
2323
+ /**
2245
2324
  * The container id of this handler.
2246
2325
  */
2247
2326
  readonly id: ContainerID;
@@ -2362,6 +2441,24 @@ export class LoroMovableList {
2362
2441
  */
2363
2442
  clear(): void;
2364
2443
  /**
2444
+ * Get the creator of the list item at the given position.
2445
+ * @param {number} pos
2446
+ * @returns {PeerID | undefined}
2447
+ */
2448
+ getCreatorAt(pos: number): PeerID | undefined;
2449
+ /**
2450
+ * Get the last mover of the list item at the given position.
2451
+ * @param {number} pos
2452
+ * @returns {PeerID | undefined}
2453
+ */
2454
+ getLastMoverAt(pos: number): PeerID | undefined;
2455
+ /**
2456
+ * Get the last editor of the list item at the given position.
2457
+ * @param {number} pos
2458
+ * @returns {PeerID | undefined}
2459
+ */
2460
+ getLastEditorAt(pos: number): PeerID | undefined;
2461
+ /**
2365
2462
  * Get the id of this container.
2366
2463
  */
2367
2464
  readonly id: ContainerID;
@@ -2402,11 +2499,14 @@ export class LoroText {
2402
2499
  */
2403
2500
  kind(): 'Text';
2404
2501
  /**
2405
- * Iterate each span(internal storage unit) of the text.
2502
+ * Iterate each text span(internal storage unit)
2406
2503
  *
2407
2504
  * The callback function will be called for each span in the text.
2408
2505
  * If the callback returns `false`, the iteration will stop.
2409
2506
  *
2507
+ * Limitation: you cannot access or alter the doc state when iterating (this is for performance consideration).
2508
+ * If you need to access or alter the doc state, please use `toString` instead.
2509
+ *
2410
2510
  * @example
2411
2511
  * ```ts
2412
2512
  * import { LoroDoc } from "loro-crdt";
@@ -2420,35 +2520,6 @@ export class LoroText {
2420
2520
  */
2421
2521
  iter(callback: Function): void;
2422
2522
  /**
2423
- * Update the current text to the target text.
2424
- *
2425
- * It will calculate the minimal difference and apply it to the current text.
2426
- * It uses Myers' diff algorithm to compute the optimal difference.
2427
- *
2428
- * This could take a long time for large texts (e.g. > 50_000 characters).
2429
- * In that case, you should use `updateByLine` instead.
2430
- *
2431
- * @example
2432
- * ```ts
2433
- * import { LoroDoc } from "loro-crdt";
2434
- *
2435
- * const doc = new LoroDoc();
2436
- * const text = doc.getText("text");
2437
- * text.insert(0, "Hello");
2438
- * text.update("Hello World");
2439
- * console.log(text.toString()); // "Hello World"
2440
- * ```
2441
- * @param {string} text
2442
- */
2443
- update(text: string): void;
2444
- /**
2445
- * Update the current text to the target text, the difference is calculated line by line.
2446
- *
2447
- * It uses Myers' diff algorithm to compute the optimal difference.
2448
- * @param {string} text
2449
- */
2450
- updateByLine(text: string): void;
2451
- /**
2452
2523
  * Insert the string at the given index (utf-16 index).
2453
2524
  *
2454
2525
  * @example
@@ -2687,6 +2758,17 @@ export class LoroText {
2687
2758
  */
2688
2759
  getAttached(): LoroText | undefined;
2689
2760
  /**
2761
+ * Push a string to the end of the text.
2762
+ * @param {string} s
2763
+ */
2764
+ push(s: string): void;
2765
+ /**
2766
+ * Get the editor of the text at the given position.
2767
+ * @param {number} pos
2768
+ * @returns {PeerID | undefined}
2769
+ */
2770
+ getEditorOf(pos: number): PeerID | undefined;
2771
+ /**
2690
2772
  * Get the container id of the text.
2691
2773
  */
2692
2774
  readonly id: ContainerID;
@@ -2956,6 +3038,21 @@ export class LoroTreeNode {
2956
3038
  */
2957
3039
  isDeleted(): boolean;
2958
3040
  /**
3041
+ * Get the last mover of this node.
3042
+ * @returns {{ peer: PeerID, counter: number } | undefined}
3043
+ */
3044
+ getLastMoveId(): { peer: PeerID, counter: number } | undefined;
3045
+ /**
3046
+ * Get the creation id of this node.
3047
+ * @returns {{ peer: PeerID, counter: number }}
3048
+ */
3049
+ creationId(): { peer: PeerID, counter: number };
3050
+ /**
3051
+ * Get the creator of this node.
3052
+ * @returns {PeerID}
3053
+ */
3054
+ creator(): PeerID;
3055
+ /**
2959
3056
  * The TreeID of the node.
2960
3057
  */
2961
3058
  readonly id: TreeID;