@loro-extended/change 5.3.0 → 5.4.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/README.md +46 -9
- package/dist/index.d.ts +174 -13
- package/dist/index.js +402 -22
- package/dist/index.js.map +1 -1
- package/package.json +3 -2
- package/src/conversion.ts +40 -4
- package/src/functional-helpers.ts +121 -7
- package/src/index.ts +14 -10
- package/src/loro.ts +2 -1
- package/src/nested-container-materialization.test.ts +336 -0
- package/src/replay-diff.test.ts +389 -0
- package/src/replay-diff.ts +229 -0
- package/src/shallow-fork.test.ts +302 -0
- package/src/typed-doc-ownkeys.test.ts +116 -0
- package/src/typed-doc.ts +10 -4
- package/src/typed-refs/base.ts +25 -4
- package/src/typed-refs/counter-ref-internals.ts +7 -2
- package/src/typed-refs/doc-ref-ownkeys.test.ts +78 -0
- package/src/typed-refs/list-ref-base-internals.ts +2 -1
- package/src/typed-refs/list-ref-base.ts +2 -1
- package/src/typed-refs/record-ref-internals.ts +104 -2
- package/src/typed-refs/record-ref.test.ts +522 -1
- package/src/typed-refs/record-ref.ts +72 -3
- package/src/typed-refs/struct-ref-internals.ts +28 -3
- package/src/typed-refs/text-ref-internals.ts +2 -2
- package/src/typed-refs/tree-node-ref-internals.ts +14 -2
- package/src/typed-refs/tree-ref-internals.ts +2 -1
- package/src/typed-refs/utils.ts +65 -8
package/README.md
CHANGED
|
@@ -605,15 +605,18 @@ loro(doc).rawValue; // Unmerged CRDT value
|
|
|
605
605
|
|
|
606
606
|
**RecordRef** (Map-like interface)
|
|
607
607
|
|
|
608
|
-
| Direct Access
|
|
609
|
-
|
|
|
610
|
-
| `get(key)`
|
|
611
|
-
| `set(key, value)`
|
|
612
|
-
| `delete(key)`
|
|
613
|
-
| `has(key)`
|
|
614
|
-
| `keys()`, `values()`
|
|
615
|
-
| `size`
|
|
616
|
-
| `
|
|
608
|
+
| Direct Access | Only via `loro()` |
|
|
609
|
+
| -------------------------------- | ------------------------------ |
|
|
610
|
+
| `get(key)` | `setContainer(key, container)` |
|
|
611
|
+
| `set(key, value)` | `subscribe(callback)` |
|
|
612
|
+
| `delete(key)` | `doc` |
|
|
613
|
+
| `has(key)` | `container` |
|
|
614
|
+
| `keys()`, `values()`, `entries()`| |
|
|
615
|
+
| `size` | |
|
|
616
|
+
| `replace(values)` | |
|
|
617
|
+
| `merge(values)` | |
|
|
618
|
+
| `clear()` | |
|
|
619
|
+
| `toJSON()` | |
|
|
617
620
|
|
|
618
621
|
**TextRef**
|
|
619
622
|
|
|
@@ -906,6 +909,40 @@ draft.metadata.values();
|
|
|
906
909
|
const value = draft.metadata.get("key");
|
|
907
910
|
```
|
|
908
911
|
|
|
912
|
+
### Record Bulk Update Operations
|
|
913
|
+
|
|
914
|
+
Records support bulk update methods for efficient batch operations:
|
|
915
|
+
|
|
916
|
+
```typescript
|
|
917
|
+
// Replace entire contents - keys not in the new object are removed
|
|
918
|
+
draft.players.replace({
|
|
919
|
+
alice: { name: "Alice", score: 100 },
|
|
920
|
+
bob: { name: "Bob", score: 50 },
|
|
921
|
+
});
|
|
922
|
+
// Result: only alice and bob exist, any previous entries are removed
|
|
923
|
+
|
|
924
|
+
// Merge values - existing keys not in the new object are kept
|
|
925
|
+
draft.scores.merge({
|
|
926
|
+
alice: 150, // updates alice
|
|
927
|
+
charlie: 25, // adds charlie
|
|
928
|
+
});
|
|
929
|
+
// Result: alice=150, bob=50 (unchanged), charlie=25
|
|
930
|
+
|
|
931
|
+
// Clear all entries
|
|
932
|
+
draft.history.clear();
|
|
933
|
+
// Result: empty record
|
|
934
|
+
```
|
|
935
|
+
|
|
936
|
+
**Method semantics:**
|
|
937
|
+
|
|
938
|
+
| Method | Adds new | Updates existing | Removes absent |
|
|
939
|
+
| ------------------ | -------- | ---------------- | -------------- |
|
|
940
|
+
| `replace(values)` | ✅ | ✅ | ✅ |
|
|
941
|
+
| `merge(values)` | ✅ | ✅ | ❌ |
|
|
942
|
+
| `clear()` | ❌ | ❌ | ✅ (all) |
|
|
943
|
+
|
|
944
|
+
These methods batch all operations into a single commit, avoiding multiple subscription notifications.
|
|
945
|
+
|
|
909
946
|
### Tree Operations
|
|
910
947
|
|
|
911
948
|
Trees are hierarchical structures where each node has typed metadata. Perfect for state machines, file systems, org charts, and nested data.
|
package/dist/index.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { PeerID, LoroDoc, Container, LoroTreeNode, TreeID, Subscription, LoroText, LoroList, LoroMovableList, LoroMap, LoroTree, LoroCounter, Value } from 'loro-crdt';
|
|
1
|
+
import { PeerID, LoroDoc, Container, LoroTreeNode, TreeID, LoroEventBatch, Subscription, LoroText, LoroList, LoroMovableList, LoroMap, LoroTree, LoroCounter, Value, ContainerID, Diff } from 'loro-crdt';
|
|
2
2
|
|
|
3
3
|
type Prev = [never, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9];
|
|
4
4
|
/**
|
|
@@ -256,6 +256,8 @@ declare const INTERNAL_SYMBOL: unique symbol;
|
|
|
256
256
|
interface RefInternalsBase {
|
|
257
257
|
/** Absorb mutated plain values back into Loro containers */
|
|
258
258
|
absorbPlainValues(): void;
|
|
259
|
+
/** Force materialization of the container and its nested containers */
|
|
260
|
+
materialize(): void;
|
|
259
261
|
}
|
|
260
262
|
type TypedRefParams<Shape extends DocShape | ContainerShape> = {
|
|
261
263
|
shape: Shape;
|
|
@@ -275,11 +277,19 @@ declare abstract class BaseRefInternals<Shape extends DocShape | ContainerShape>
|
|
|
275
277
|
protected readonly params: TypedRefParams<Shape>;
|
|
276
278
|
protected cachedContainer: ShapeToContainer<Shape> | undefined;
|
|
277
279
|
protected loroNamespace: LoroRefBase | undefined;
|
|
280
|
+
private _suppressAutoCommit;
|
|
278
281
|
constructor(params: TypedRefParams<Shape>);
|
|
279
282
|
/** Get the underlying Loro container (cached) */
|
|
280
283
|
getContainer(): ShapeToContainer<Shape>;
|
|
281
|
-
/** Commit changes if autoCommit is enabled */
|
|
284
|
+
/** Commit changes if autoCommit is enabled and not suppressed */
|
|
282
285
|
commitIfAuto(): void;
|
|
286
|
+
/**
|
|
287
|
+
* Temporarily suppress auto-commit during batch operations.
|
|
288
|
+
* Used by assignPlainValueToTypedRef() to batch multiple property assignments.
|
|
289
|
+
*/
|
|
290
|
+
setSuppressAutoCommit(suppress: boolean): void;
|
|
291
|
+
/** Check if auto-commit is currently suppressed */
|
|
292
|
+
isSuppressAutoCommit(): boolean;
|
|
283
293
|
/** Get the shape for this ref */
|
|
284
294
|
getShape(): Shape;
|
|
285
295
|
/** Get the placeholder value */
|
|
@@ -302,6 +312,8 @@ declare abstract class BaseRefInternals<Shape extends DocShape | ContainerShape>
|
|
|
302
312
|
getLoroNamespace(): LoroRefBase;
|
|
303
313
|
/** Absorb mutated plain values back into Loro containers - subclasses override */
|
|
304
314
|
abstract absorbPlainValues(): void;
|
|
315
|
+
/** Force materialization of the container and its nested containers */
|
|
316
|
+
materialize(): void;
|
|
305
317
|
/** Create the loro() namespace object - subclasses override for specific types */
|
|
306
318
|
protected createLoroNamespace(): LoroRefBase;
|
|
307
319
|
}
|
|
@@ -480,6 +492,20 @@ declare class RecordRefInternals<NestedShape extends ContainerOrValueShape> exte
|
|
|
480
492
|
set(key: string, value: any): void;
|
|
481
493
|
/** Delete a key */
|
|
482
494
|
delete(key: string): void;
|
|
495
|
+
/**
|
|
496
|
+
* Replace entire contents with new values.
|
|
497
|
+
* Keys not in `values` are removed.
|
|
498
|
+
*/
|
|
499
|
+
replace(values: Record<string, any>): void;
|
|
500
|
+
/**
|
|
501
|
+
* Merge values into record.
|
|
502
|
+
* Existing keys not in `values` are kept.
|
|
503
|
+
*/
|
|
504
|
+
merge(values: Record<string, any>): void;
|
|
505
|
+
/**
|
|
506
|
+
* Remove all entries from the record.
|
|
507
|
+
*/
|
|
508
|
+
clear(): void;
|
|
483
509
|
/** Absorb mutated plain values back into Loro containers */
|
|
484
510
|
absorbPlainValues(): void;
|
|
485
511
|
/** Create the loro namespace for record */
|
|
@@ -501,8 +527,59 @@ declare class RecordRef<NestedShape extends ContainerOrValueShape> extends Typed
|
|
|
501
527
|
setContainer<C extends Container>(key: string, container: C): C;
|
|
502
528
|
has(key: string): boolean;
|
|
503
529
|
keys(): string[];
|
|
504
|
-
|
|
530
|
+
/**
|
|
531
|
+
* Returns an array of all values in the record.
|
|
532
|
+
* For container-valued records, returns properly typed refs.
|
|
533
|
+
*/
|
|
534
|
+
values(): InferMutableType<NestedShape>[];
|
|
535
|
+
/**
|
|
536
|
+
* Returns an array of [key, value] pairs.
|
|
537
|
+
* For container-valued records, values are properly typed refs.
|
|
538
|
+
*/
|
|
539
|
+
entries(): [string, InferMutableType<NestedShape>][];
|
|
505
540
|
get size(): number;
|
|
541
|
+
/**
|
|
542
|
+
* Replace entire contents with new values.
|
|
543
|
+
* Keys not in `values` are removed.
|
|
544
|
+
*
|
|
545
|
+
* @example
|
|
546
|
+
* ```typescript
|
|
547
|
+
* doc.change(draft => {
|
|
548
|
+
* draft.players.replace({
|
|
549
|
+
* alice: { score: 100 },
|
|
550
|
+
* bob: { score: 50 }
|
|
551
|
+
* })
|
|
552
|
+
* })
|
|
553
|
+
* ```
|
|
554
|
+
*/
|
|
555
|
+
replace(values: Record<string, Infer<NestedShape>>): void;
|
|
556
|
+
/**
|
|
557
|
+
* Merge values into record.
|
|
558
|
+
* Existing keys not in `values` are kept.
|
|
559
|
+
*
|
|
560
|
+
* @example
|
|
561
|
+
* ```typescript
|
|
562
|
+
* doc.change(draft => {
|
|
563
|
+
* // Adds charlie, updates alice, keeps bob unchanged
|
|
564
|
+
* draft.players.merge({
|
|
565
|
+
* alice: { score: 150 },
|
|
566
|
+
* charlie: { score: 25 }
|
|
567
|
+
* })
|
|
568
|
+
* })
|
|
569
|
+
* ```
|
|
570
|
+
*/
|
|
571
|
+
merge(values: Record<string, Infer<NestedShape>>): void;
|
|
572
|
+
/**
|
|
573
|
+
* Remove all entries from the record.
|
|
574
|
+
*
|
|
575
|
+
* @example
|
|
576
|
+
* ```typescript
|
|
577
|
+
* doc.change(draft => {
|
|
578
|
+
* draft.players.clear()
|
|
579
|
+
* })
|
|
580
|
+
* ```
|
|
581
|
+
*/
|
|
582
|
+
clear(): void;
|
|
506
583
|
toJSON(): Record<string, Infer<NestedShape>>;
|
|
507
584
|
}
|
|
508
585
|
|
|
@@ -667,6 +744,8 @@ declare class TreeNodeRefInternals<DataShape extends StructContainerShape> imple
|
|
|
667
744
|
getOrCreateDataRef(): StructRef<DataShape["shapes"]>;
|
|
668
745
|
/** Absorb mutated plain values back into Loro containers */
|
|
669
746
|
absorbPlainValues(): void;
|
|
747
|
+
/** Force materialization of the container and its nested containers */
|
|
748
|
+
materialize(): void;
|
|
670
749
|
/** Get the loro namespace (cached) */
|
|
671
750
|
getLoroNamespace(): LoroTreeNodeRef;
|
|
672
751
|
/** Create the loro namespace for tree node */
|
|
@@ -930,7 +1009,7 @@ interface LoroRefBase {
|
|
|
930
1009
|
* @param callback - Function called when the container changes
|
|
931
1010
|
* @returns Subscription that can be used to unsubscribe
|
|
932
1011
|
*/
|
|
933
|
-
subscribe(callback: (event:
|
|
1012
|
+
subscribe(callback: (event: LoroEventBatch) => void): Subscription;
|
|
934
1013
|
}
|
|
935
1014
|
/**
|
|
936
1015
|
* loro() return type for ListRef and MovableListRef.
|
|
@@ -1159,10 +1238,6 @@ interface MovableListContainerShape<NestedShape extends ContainerOrValueShape =
|
|
|
1159
1238
|
readonly _type: "movableList";
|
|
1160
1239
|
readonly shape: NestedShape;
|
|
1161
1240
|
}
|
|
1162
|
-
/**
|
|
1163
|
-
* @deprecated Use StructContainerShape instead. MapContainerShape is an alias for backward compatibility.
|
|
1164
|
-
*/
|
|
1165
|
-
type MapContainerShape<NestedShapes extends Record<string, ContainerOrValueShape> = Record<string, ContainerOrValueShape>> = StructContainerShape<NestedShapes>;
|
|
1166
1241
|
/**
|
|
1167
1242
|
* Container shape for objects with fixed keys (structs).
|
|
1168
1243
|
* This is the preferred way to define fixed-key objects.
|
|
@@ -1243,10 +1318,6 @@ interface Uint8ArrayValueShape extends Shape<Uint8Array, Uint8Array, Uint8Array>
|
|
|
1243
1318
|
readonly _type: "value";
|
|
1244
1319
|
readonly valueType: "uint8array";
|
|
1245
1320
|
}
|
|
1246
|
-
/**
|
|
1247
|
-
* @deprecated Use StructValueShape instead. ObjectValueShape is an alias for backward compatibility.
|
|
1248
|
-
*/
|
|
1249
|
-
type ObjectValueShape<T extends Record<string, ValueShape> = Record<string, ValueShape>> = StructValueShape<T>;
|
|
1250
1321
|
/**
|
|
1251
1322
|
* Value shape for objects with fixed keys (structs).
|
|
1252
1323
|
* This is the preferred way to define fixed-key plain value objects.
|
|
@@ -1600,6 +1671,39 @@ declare function getLoroContainer<NestedShapes extends Record<string, ContainerO
|
|
|
1600
1671
|
declare function getLoroContainer<DataShape extends StructContainerShape>(ref: TreeRef<DataShape>): LoroTree;
|
|
1601
1672
|
declare function getLoroContainer<DataShape extends StructContainerShape>(ref: TreeRefInterface<DataShape>): LoroTree;
|
|
1602
1673
|
declare function getLoroContainer<Shape extends ContainerShape>(ref: TypedRef<Shape>): ShapeToContainer<Shape>;
|
|
1674
|
+
/**
|
|
1675
|
+
* Creates a new TypedDoc as a fork of the current document.
|
|
1676
|
+
* The forked doc contains all history up to the current version.
|
|
1677
|
+
* The forked doc has a different PeerID from the original by default.
|
|
1678
|
+
*
|
|
1679
|
+
* For raw LoroDoc access, use: `loro(doc).doc.fork()`
|
|
1680
|
+
*
|
|
1681
|
+
* @param doc - The TypedDoc to fork
|
|
1682
|
+
* @param options - Optional settings
|
|
1683
|
+
* @param options.preservePeerId - If true, copies the original doc's peer ID to the fork
|
|
1684
|
+
* @returns A new TypedDoc with the same schema at the current version
|
|
1685
|
+
*
|
|
1686
|
+
* @example
|
|
1687
|
+
* ```typescript
|
|
1688
|
+
* import { fork, loro } from "@loro-extended/change"
|
|
1689
|
+
*
|
|
1690
|
+
* const doc = createTypedDoc(schema);
|
|
1691
|
+
* doc.title.update("Hello");
|
|
1692
|
+
*
|
|
1693
|
+
* // Fork the document
|
|
1694
|
+
* const forkedDoc = fork(doc);
|
|
1695
|
+
* forkedDoc.title.update("World");
|
|
1696
|
+
*
|
|
1697
|
+
* console.log(doc.title.toString()); // "Hello"
|
|
1698
|
+
* console.log(forkedDoc.title.toString()); // "World"
|
|
1699
|
+
*
|
|
1700
|
+
* // Fork with same peer ID (for World/Worldview pattern)
|
|
1701
|
+
* const worldview = fork(world, { preservePeerId: true });
|
|
1702
|
+
* ```
|
|
1703
|
+
*/
|
|
1704
|
+
declare function fork<Shape extends DocShape>(doc: TypedDoc<Shape>, options?: {
|
|
1705
|
+
preservePeerId?: boolean;
|
|
1706
|
+
}): TypedDoc<Shape>;
|
|
1603
1707
|
/**
|
|
1604
1708
|
* Creates a new TypedDoc at a specified version (frontiers).
|
|
1605
1709
|
* The forked doc will only contain history before the specified frontiers.
|
|
@@ -1627,6 +1731,52 @@ declare function getLoroContainer<Shape extends ContainerShape>(ref: TypedRef<Sh
|
|
|
1627
1731
|
* ```
|
|
1628
1732
|
*/
|
|
1629
1733
|
declare function forkAt<Shape extends DocShape>(doc: TypedDoc<Shape>, frontiers: Frontiers): TypedDoc<Shape>;
|
|
1734
|
+
/**
|
|
1735
|
+
* Creates a new TypedDoc at a specified version using a shallow snapshot.
|
|
1736
|
+
* Unlike `forkAt`, this creates a "garbage-collected" snapshot that only
|
|
1737
|
+
* contains the current state and history since the specified frontiers.
|
|
1738
|
+
*
|
|
1739
|
+
* This is more memory-efficient than `forkAt` for documents with long history,
|
|
1740
|
+
* especially useful for the fork-and-merge pattern in LEA where we only need:
|
|
1741
|
+
* 1. Read current state
|
|
1742
|
+
* 2. Apply changes
|
|
1743
|
+
* 3. Export delta and merge back
|
|
1744
|
+
*
|
|
1745
|
+
* The shallow fork has a different PeerID from the original by default.
|
|
1746
|
+
* Use `preservePeerId: true` to copy the original's peer ID (useful for
|
|
1747
|
+
* fork-and-merge patterns where you want consistent frontier progression).
|
|
1748
|
+
*
|
|
1749
|
+
* @param doc - The TypedDoc to fork
|
|
1750
|
+
* @param frontiers - The version to fork at (obtained from `loro(doc).doc.frontiers()`)
|
|
1751
|
+
* @param options - Optional settings
|
|
1752
|
+
* @param options.preservePeerId - If true, copies the original doc's peer ID to the fork
|
|
1753
|
+
* @returns A new TypedDoc with the same schema at the specified version (shallow)
|
|
1754
|
+
*
|
|
1755
|
+
* @example
|
|
1756
|
+
* ```typescript
|
|
1757
|
+
* import { shallowForkAt, loro } from "@loro-extended/change"
|
|
1758
|
+
*
|
|
1759
|
+
* const doc = createTypedDoc(schema);
|
|
1760
|
+
* doc.title.update("Hello");
|
|
1761
|
+
* const frontiers = loro(doc).doc.frontiers();
|
|
1762
|
+
*
|
|
1763
|
+
* // Create a shallow fork (memory-efficient)
|
|
1764
|
+
* const shallowDoc = shallowForkAt(doc, frontiers, { preservePeerId: true });
|
|
1765
|
+
*
|
|
1766
|
+
* // Modify the shallow doc
|
|
1767
|
+
* shallowDoc.title.update("World");
|
|
1768
|
+
*
|
|
1769
|
+
* // Merge changes back
|
|
1770
|
+
* const update = loro(shallowDoc).doc.export({
|
|
1771
|
+
* mode: "update",
|
|
1772
|
+
* from: loro(doc).doc.version()
|
|
1773
|
+
* });
|
|
1774
|
+
* loro(doc).doc.import(update);
|
|
1775
|
+
* ```
|
|
1776
|
+
*/
|
|
1777
|
+
declare function shallowForkAt<Shape extends DocShape>(doc: TypedDoc<Shape>, frontiers: Frontiers, options?: {
|
|
1778
|
+
preservePeerId?: boolean;
|
|
1779
|
+
}): TypedDoc<Shape>;
|
|
1630
1780
|
|
|
1631
1781
|
/**
|
|
1632
1782
|
* Overlays CRDT state with placeholder defaults
|
|
@@ -1763,10 +1913,21 @@ declare function evaluatePathOnValue(value: unknown, segments: PathSegment[]): u
|
|
|
1763
1913
|
*/
|
|
1764
1914
|
declare function createPlaceholderProxy<T extends object>(target: T): T;
|
|
1765
1915
|
|
|
1916
|
+
/**
|
|
1917
|
+
* Replay a diff as local operations on a document.
|
|
1918
|
+
*
|
|
1919
|
+
* Unlike doc.import() which creates import events, this creates LOCAL events
|
|
1920
|
+
* that are captured by subscribeLocalUpdates() and UndoManager.
|
|
1921
|
+
*
|
|
1922
|
+
* @param doc - The target document to apply changes to
|
|
1923
|
+
* @param diff - The diff from doc.diff(from, to, false)
|
|
1924
|
+
*/
|
|
1925
|
+
declare function replayDiff(doc: LoroDoc, diff: [ContainerID, Diff][]): void;
|
|
1926
|
+
|
|
1766
1927
|
/**
|
|
1767
1928
|
* Validates placeholder against schema structure without using Zod
|
|
1768
1929
|
* Combines the functionality of createPlaceholderValidator and createValueValidator
|
|
1769
1930
|
*/
|
|
1770
1931
|
declare function validatePlaceholder<T extends DocShape>(placeholder: unknown, schema: T): Infer<T>;
|
|
1771
1932
|
|
|
1772
|
-
export { type AnyContainerShape, type AnyValueShape, type ArrayValueShape, type ContainerOrValueShape, type ContainerShape, type CounterContainerShape, CounterRef, type DiscriminatedUnionValueShape, type DocShape, type Frontiers, type Infer, type InferMutableType, type InferPlaceholderType, type InferRaw, LORO_SYMBOL, type ListContainerShape, ListRef, type LoroCounterRef, type LoroListRef, type LoroMapRef, type LoroRefBase, type LoroTextRef, type LoroTreeRef, type LoroTypedDocRef, type
|
|
1933
|
+
export { type AnyContainerShape, type AnyValueShape, type ArrayValueShape, type ContainerOrValueShape, type ContainerShape, type CounterContainerShape, CounterRef, type DiscriminatedUnionValueShape, type DocShape, type Frontiers, type Infer, type InferMutableType, type InferPlaceholderType, type InferRaw, LORO_SYMBOL, type ListContainerShape, ListRef, type LoroCounterRef, type LoroListRef, type LoroMapRef, type LoroRefBase, type LoroTextRef, type LoroTreeRef, type LoroTypedDocRef, type MovableListContainerShape, MovableListRef, type Mutable, type NumberValueShape, type PathBuilder, type PathNode, type PathSegment, type PathSelector, type RecordContainerShape, RecordRef, type RecordValueShape, type ContainerType as RootContainerType, Shape, type StringValueShape, type StructContainerShape, type StructRef, type StructValueShape, type TextContainerShape, TextRef, type TreeContainerShape, type TreeNodeJSON, TreeNodeRef, TreeRef, type TreeRefInterface, type TypedDoc, type UnionValueShape, type ValueShape, type WithNullable, type WithPlaceholder, change, compileToJsonPath, createPathBuilder, createPlaceholderProxy, createTypedDoc, derivePlaceholder, deriveShapePlaceholder, evaluatePath, evaluatePathOnValue, fork, forkAt, getLoroContainer, getLoroDoc, hasWildcard, loro, mergeValue, overlayPlaceholder, replayDiff, shallowForkAt, validatePlaceholder };
|