loro-crdt 0.10.1 → 0.11.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 +16 -0
- package/dist/loro.d.ts +51 -29
- package/dist/loro.js.map +1 -1
- package/dist/loro.mjs.map +1 -1
- package/package.json +2 -2
- package/src/index.ts +62 -34
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,21 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## 0.11.0
|
|
4
|
+
|
|
5
|
+
### Minor Changes
|
|
6
|
+
|
|
7
|
+
- Fix a few bugs and include BREAKING CHANG refactors
|
|
8
|
+
|
|
9
|
+
- fix: should not reset the state when calling checkout to latest (#265)
|
|
10
|
+
- refactor: only send a event for one `import`/`transaction`/`checkout` (#263)
|
|
11
|
+
- perf: optimize snapshot encoding speed (#264)
|
|
12
|
+
- feat: remove deleted set in tree state and optimize api (#259)
|
|
13
|
+
|
|
14
|
+
### Patch Changes
|
|
15
|
+
|
|
16
|
+
- Updated dependencies
|
|
17
|
+
- loro-wasm@0.11.0
|
|
18
|
+
|
|
3
19
|
## 0.10.1
|
|
4
20
|
|
|
5
21
|
### Patch Changes
|
package/dist/loro.d.ts
CHANGED
|
@@ -5,36 +5,46 @@ export { Loro } from 'loro-wasm';
|
|
|
5
5
|
type Frontiers = OpId[];
|
|
6
6
|
/**
|
|
7
7
|
* Represents a path to identify the exact location of an event's target.
|
|
8
|
-
* The path is composed of numbers (e.g., indices of a list container)
|
|
9
|
-
* (e.g., keys of a map container)
|
|
10
|
-
* within a loro document.
|
|
8
|
+
* The path is composed of numbers (e.g., indices of a list container) strings
|
|
9
|
+
* (e.g., keys of a map container) and TreeID (the node of a tree container),
|
|
10
|
+
* indicating the absolute position of the event's source within a loro document.
|
|
11
11
|
*/
|
|
12
|
-
type Path = (number | string)[];
|
|
12
|
+
type Path = (number | string | TreeID)[];
|
|
13
13
|
/**
|
|
14
|
-
*
|
|
14
|
+
* A batch of events that created by a single `import`/`transaction`/`checkout`.
|
|
15
|
+
*
|
|
15
16
|
* @prop local - Indicates whether the event is local.
|
|
16
17
|
* @prop origin - (Optional) Provides information about the origin of the event.
|
|
17
18
|
* @prop diff - Contains the differential information related to the event.
|
|
18
19
|
* @prop target - Identifies the container ID of the event's target.
|
|
19
20
|
* @prop path - Specifies the absolute path of the event's emitter, which can be an index of a list container or a key of a map container.
|
|
20
21
|
*/
|
|
21
|
-
interface
|
|
22
|
+
interface LoroEventBatch {
|
|
23
|
+
local: boolean;
|
|
22
24
|
/**
|
|
23
|
-
*
|
|
25
|
+
* If true, this event was triggered by a checkout.
|
|
24
26
|
*/
|
|
25
|
-
|
|
26
|
-
local: boolean;
|
|
27
|
+
fromCheckout: boolean;
|
|
27
28
|
origin?: string;
|
|
28
29
|
/**
|
|
29
|
-
*
|
|
30
|
+
* The container ID of the current event receiver.
|
|
31
|
+
* It's undefined if the subscriber is on the root document.
|
|
30
32
|
*/
|
|
31
|
-
|
|
33
|
+
currentTarget?: ContainerID;
|
|
34
|
+
events: LoroEvent[];
|
|
35
|
+
}
|
|
36
|
+
/**
|
|
37
|
+
* The concrete event of Loro.
|
|
38
|
+
*/
|
|
39
|
+
interface LoroEvent {
|
|
32
40
|
/**
|
|
33
|
-
*
|
|
41
|
+
* The container ID of the event's target.
|
|
34
42
|
*/
|
|
35
|
-
fromCheckout: boolean;
|
|
36
|
-
diff: Diff;
|
|
37
43
|
target: ContainerID;
|
|
44
|
+
diff: Diff;
|
|
45
|
+
/**
|
|
46
|
+
* The absolute path of the event's emitter, which can be an index of a list container or a key of a map container.
|
|
47
|
+
*/
|
|
38
48
|
path: Path;
|
|
39
49
|
}
|
|
40
50
|
type ListDiff = {
|
|
@@ -49,20 +59,25 @@ type MapDiff = {
|
|
|
49
59
|
type: "map";
|
|
50
60
|
updated: Record<string, Value | Container | undefined>;
|
|
51
61
|
};
|
|
62
|
+
type TreeDiffItem = {
|
|
63
|
+
target: TreeID;
|
|
64
|
+
action: "create";
|
|
65
|
+
parent: TreeID | undefined;
|
|
66
|
+
} | {
|
|
67
|
+
target: TreeID;
|
|
68
|
+
action: "delete";
|
|
69
|
+
} | {
|
|
70
|
+
target: TreeID;
|
|
71
|
+
action: "move";
|
|
72
|
+
parent: TreeID | undefined;
|
|
73
|
+
};
|
|
52
74
|
type TreeDiff = {
|
|
53
75
|
type: "tree";
|
|
54
|
-
diff:
|
|
55
|
-
target: TreeID;
|
|
56
|
-
action: "create" | "delete";
|
|
57
|
-
} | {
|
|
58
|
-
target: TreeID;
|
|
59
|
-
action: "move";
|
|
60
|
-
parent: TreeID;
|
|
61
|
-
};
|
|
76
|
+
diff: TreeDiffItem[];
|
|
62
77
|
};
|
|
63
78
|
type Diff = ListDiff | TextDiff | MapDiff | TreeDiff;
|
|
64
79
|
interface Listener {
|
|
65
|
-
(event:
|
|
80
|
+
(event: LoroEventBatch): void;
|
|
66
81
|
}
|
|
67
82
|
declare function isContainerId(s: string): s is ContainerID;
|
|
68
83
|
|
|
@@ -141,14 +156,21 @@ declare module "loro-wasm" {
|
|
|
141
156
|
subscribe(txn: Loro, listener: Listener): number;
|
|
142
157
|
}
|
|
143
158
|
interface LoroTree {
|
|
144
|
-
|
|
145
|
-
|
|
159
|
+
createNode(parent: TreeID | undefined): LoroTreeNode;
|
|
160
|
+
move(target: TreeID, parent: TreeID | undefined): void;
|
|
146
161
|
delete(target: TreeID): void;
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
contains(target: TreeID): boolean;
|
|
162
|
+
has(target: TreeID): boolean;
|
|
163
|
+
getNodeByID(target: TreeID): LoroTreeNode;
|
|
150
164
|
subscribe(txn: Loro, listener: Listener): number;
|
|
151
165
|
}
|
|
166
|
+
interface LoroTreeNode {
|
|
167
|
+
readonly data: LoroMap;
|
|
168
|
+
createNode(): LoroTreeNode;
|
|
169
|
+
setAsRoot(): void;
|
|
170
|
+
moveTo(parent: LoroTreeNode): void;
|
|
171
|
+
parent(): LoroTreeNode | undefined;
|
|
172
|
+
children(): Array<LoroTreeNode>;
|
|
173
|
+
}
|
|
152
174
|
}
|
|
153
175
|
|
|
154
|
-
export { Diff, Frontiers, ListDiff, LoroEvent, MapDiff, Path, TextDiff, TreeDiff, getType, isContainer, isContainerId };
|
|
176
|
+
export { Diff, Frontiers, ListDiff, LoroEvent, LoroEventBatch, MapDiff, Path, TextDiff, TreeDiff, TreeDiffItem, getType, isContainer, isContainerId };
|
package/dist/loro.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"loro.js","sources":["../src/index.ts"],"sourcesContent":["export * from \"loro-wasm\";\nimport { Container, Delta, LoroText, LoroTree, OpId, Value, ContainerID, Loro, LoroList, LoroMap, TreeID } from \"loro-wasm\";\n\n\nLoro.prototype.getTypedMap = function (...args) {\n return this.getMap(...args);\n};\nLoro.prototype.getTypedList = function (...args) {\n return this.getList(...args);\n};\nLoroList.prototype.getTyped = function (loro, index) {\n const value = this.get(index);\n if (typeof value === \"string\" && isContainerId(value)) {\n return loro.getContainerById(value);\n } else {\n return value;\n }\n};\nLoroList.prototype.insertTyped = function (...args) {\n return this.insert(...args);\n};\nLoroMap.prototype.getTyped = function (loro, key) {\n const value = this.get(key);\n if (typeof value === \"string\" && isContainerId(value)) {\n return loro.getContainerById(value);\n } else {\n return value;\n }\n};\nLoroMap.prototype.setTyped = function (...args) {\n return this.set(...args);\n};\n\nexport type Frontiers = OpId[];\n\n/**\n * Represents a path to identify the exact location of an event's target.\n * The path is composed of numbers (e.g., indices of a list container)
|
|
1
|
+
{"version":3,"file":"loro.js","sources":["../src/index.ts"],"sourcesContent":["export * from \"loro-wasm\";\nimport { Container, Delta, LoroText, LoroTree,LoroTreeNode, OpId, Value, ContainerID, Loro, LoroList, LoroMap, TreeID } from \"loro-wasm\";\n\n\nLoro.prototype.getTypedMap = function (...args) {\n return this.getMap(...args);\n};\nLoro.prototype.getTypedList = function (...args) {\n return this.getList(...args);\n};\nLoroList.prototype.getTyped = function (loro, index) {\n const value = this.get(index);\n if (typeof value === \"string\" && isContainerId(value)) {\n return loro.getContainerById(value);\n } else {\n return value;\n }\n};\nLoroList.prototype.insertTyped = function (...args) {\n return this.insert(...args);\n};\nLoroMap.prototype.getTyped = function (loro, key) {\n const value = this.get(key);\n if (typeof value === \"string\" && isContainerId(value)) {\n return loro.getContainerById(value);\n } else {\n return value;\n }\n};\nLoroMap.prototype.setTyped = function (...args) {\n return this.set(...args);\n};\n\nexport type Frontiers = OpId[];\n\n/**\n * Represents a path to identify the exact location of an event's target.\n * The path is composed of numbers (e.g., indices of a list container) strings\n * (e.g., keys of a map container) and TreeID (the node of a tree container), \n * indicating the absolute position of the event's source within a loro document.\n */\nexport type Path = (number | string | TreeID )[];\n\n/**\n * A batch of events that created by a single `import`/`transaction`/`checkout`.\n *\n * @prop local - Indicates whether the event is local.\n * @prop origin - (Optional) Provides information about the origin of the event.\n * @prop diff - Contains the differential information related to the event.\n * @prop target - Identifies the container ID of the event's target.\n * @prop path - Specifies the absolute path of the event's emitter, which can be an index of a list container or a key of a map container.\n */\nexport interface LoroEventBatch {\n local: boolean;\n /**\n * If true, this event was triggered by a checkout.\n */\n fromCheckout: boolean;\n origin?: string;\n /**\n * The container ID of the current event receiver.\n * It's undefined if the subscriber is on the root document.\n */\n currentTarget?: ContainerID;\n events: LoroEvent[];\n}\n\n/**\n * The concrete event of Loro.\n */\nexport interface LoroEvent {\n /**\n * The container ID of the event's target.\n */\n target: ContainerID;\n diff: Diff;\n /**\n * The absolute path of the event's emitter, which can be an index of a list container or a key of a map container.\n */\n path: Path;\n}\n\nexport type ListDiff = {\n type: \"list\";\n diff: Delta<(Value | Container)[]>[];\n};\n\nexport type TextDiff = {\n type: \"text\";\n diff: Delta<string>[];\n};\n\nexport type MapDiff = {\n type: \"map\";\n updated: Record<string, Value | Container | undefined>;\n};\n\nexport type TreeDiffItem = { target: TreeID; action: \"create\"; parent: TreeID | undefined }\n | { target: TreeID; action: \"delete\" }\n | { target: TreeID; action: \"move\"; parent: TreeID | undefined };\n\nexport type TreeDiff = {\n type: \"tree\";\n diff: TreeDiffItem[];\n};\n\nexport type Diff = ListDiff | TextDiff | MapDiff | TreeDiff;\n\ninterface Listener {\n (event: LoroEventBatch): void;\n}\n\nconst CONTAINER_TYPES = [\"Map\", \"Text\", \"List\", \"Tree\"];\n\nexport function isContainerId(s: string): s is ContainerID {\n return s.startsWith(\"cid:\");\n}\n\nexport { Loro };\n\n/** Whether the value is a container.\n *\n * # Example\n *\n * ```ts\n * const doc = new Loro();\n * const map = doc.getMap(\"map\");\n * const list = doc.getList(\"list\");\n * const text = doc.getText(\"text\");\n * isContainer(map); // true\n * isContainer(list); // true\n * isContainer(text); // true\n * isContainer(123); // false\n * isContainer(\"123\"); // false\n * isContainer({}); // false\n */\nexport function isContainer(value: any): value is Container {\n if (typeof value !== \"object\" || value == null) {\n return false;\n }\n\n const p = Object.getPrototypeOf(value);\n if (p == null || typeof p !== \"object\" || typeof p[\"kind\"] !== \"function\") {\n return false;\n }\n\n return CONTAINER_TYPES.includes(value.kind());\n}\n\n/** Get the type of a value that may be a container.\n *\n * # Example\n *\n * ```ts\n * const doc = new Loro();\n * const map = doc.getMap(\"map\");\n * const list = doc.getList(\"list\");\n * const text = doc.getText(\"text\");\n * getType(map); // \"Map\"\n * getType(list); // \"List\"\n * getType(text); // \"Text\"\n * getType(123); // \"Json\"\n * getType(\"123\"); // \"Json\"\n * getType({}); // \"Json\"\n * ```\n */\nexport function getType<T>(\n value: T,\n): T extends LoroText\n ? \"Text\"\n : T extends LoroMap\n ? \"Map\"\n : T extends LoroTree\n ? \"Tree\"\n : T extends LoroList\n ? \"List\"\n : \"Json\" {\n if (isContainer(value)) {\n return value.kind();\n }\n\n return \"Json\" as any;\n}\n\ndeclare module \"loro-wasm\" {\n interface Loro {\n subscribe(listener: Listener): number;\n }\n\n interface Loro<T extends Record<string, any> = Record<string, any>> {\n getTypedMap<Key extends keyof T & string>(\n name: Key,\n ): T[Key] extends LoroMap ? T[Key] : never;\n getTypedList<Key extends keyof T & string>(\n name: Key,\n ): T[Key] extends LoroList ? T[Key] : never;\n }\n\n interface LoroList<T extends any[] = any[]> {\n insertContainer(pos: number, container: \"Map\"): LoroMap;\n insertContainer(pos: number, container: \"List\"): LoroList;\n insertContainer(pos: number, container: \"Text\"): LoroText;\n insertContainer(pos: number, container: \"Tree\"): LoroTree;\n insertContainer(pos: number, container: string): never;\n\n get(index: number): undefined | Value | Container;\n getTyped<Key extends keyof T & number>(loro: Loro, index: Key): T[Key];\n insertTyped<Key extends keyof T & number>(pos: Key, value: T[Key]): void;\n insert(pos: number, value: Value): void;\n delete(pos: number, len: number): void;\n subscribe(txn: Loro, listener: Listener): number;\n }\n\n interface LoroMap<T extends Record<string, any> = Record<string, any>> {\n setContainer(key: string, container_type: \"Map\"): LoroMap;\n setContainer(key: string, container_type: \"List\"): LoroList;\n setContainer(key: string, container_type: \"Text\"): LoroText;\n setContainer(key: string, container_type: \"Tree\"): LoroTree;\n setContainer(key: string, container_type: string): never;\n\n get(key: string): undefined | Value | Container;\n getTyped<Key extends keyof T & string>(txn: Loro, key: Key): T[Key];\n set(key: string, value: Value): void;\n setTyped<Key extends keyof T & string>(key: Key, value: T[Key]): void;\n delete(key: string): void;\n subscribe(txn: Loro, listener: Listener): number;\n }\n\n interface LoroText {\n insert(pos: number, text: string): void;\n delete(pos: number, len: number): void;\n subscribe(txn: Loro, listener: Listener): number;\n }\n\n interface LoroTree {\n createNode(parent: TreeID | undefined): LoroTreeNode;\n move(target: TreeID, parent: TreeID | undefined): void;\n delete(target: TreeID): void;\n has(target: TreeID): boolean;\n getNodeByID(target: TreeID): LoroTreeNode;\n subscribe(txn: Loro, listener: Listener): number;\n }\n\n interface LoroTreeNode{\n readonly data: LoroMap;\n createNode(): LoroTreeNode;\n setAsRoot(): void;\n moveTo(parent: LoroTreeNode): void;\n parent(): LoroTreeNode | undefined;\n children(): Array<LoroTreeNode>;\n }\n}\n"],"names":["Loro","LoroList","LoroMap"],"mappings":";;;;AAIAA,aAAK,CAAA,SAAA,CAAU,WAAc,GAAA,SAAA,GAAa,IAAM,EAAA;AAC9C,EAAO,OAAA,IAAA,CAAK,MAAO,CAAA,GAAG,IAAI,CAAA,CAAA;AAC5B,CAAA,CAAA;AACAA,aAAK,CAAA,SAAA,CAAU,YAAe,GAAA,SAAA,GAAa,IAAM,EAAA;AAC/C,EAAO,OAAA,IAAA,CAAK,OAAQ,CAAA,GAAG,IAAI,CAAA,CAAA;AAC7B,CAAA,CAAA;AACAC,iBAAA,CAAS,SAAU,CAAA,QAAA,GAAW,SAAU,IAAA,EAAM,KAAO,EAAA;AACnD,EAAM,MAAA,KAAA,GAAQ,IAAK,CAAA,GAAA,CAAI,KAAK,CAAA,CAAA;AAC5B,EAAA,IAAI,OAAO,KAAA,KAAU,QAAY,IAAA,aAAA,CAAc,KAAK,CAAG,EAAA;AACrD,IAAO,OAAA,IAAA,CAAK,iBAAiB,KAAK,CAAA,CAAA;AAAA,GAC7B,MAAA;AACL,IAAO,OAAA,KAAA,CAAA;AAAA,GACT;AACF,CAAA,CAAA;AACAA,iBAAS,CAAA,SAAA,CAAU,WAAc,GAAA,SAAA,GAAa,IAAM,EAAA;AAClD,EAAO,OAAA,IAAA,CAAK,MAAO,CAAA,GAAG,IAAI,CAAA,CAAA;AAC5B,CAAA,CAAA;AACAC,gBAAA,CAAQ,SAAU,CAAA,QAAA,GAAW,SAAU,IAAA,EAAM,GAAK,EAAA;AAChD,EAAM,MAAA,KAAA,GAAQ,IAAK,CAAA,GAAA,CAAI,GAAG,CAAA,CAAA;AAC1B,EAAA,IAAI,OAAO,KAAA,KAAU,QAAY,IAAA,aAAA,CAAc,KAAK,CAAG,EAAA;AACrD,IAAO,OAAA,IAAA,CAAK,iBAAiB,KAAK,CAAA,CAAA;AAAA,GAC7B,MAAA;AACL,IAAO,OAAA,KAAA,CAAA;AAAA,GACT;AACF,CAAA,CAAA;AACAA,gBAAQ,CAAA,SAAA,CAAU,QAAW,GAAA,SAAA,GAAa,IAAM,EAAA;AAC9C,EAAO,OAAA,IAAA,CAAK,GAAI,CAAA,GAAG,IAAI,CAAA,CAAA;AACzB,CAAA,CAAA;AAiFA,MAAM,eAAkB,GAAA,CAAC,KAAO,EAAA,MAAA,EAAQ,QAAQ,MAAM,CAAA,CAAA;AAE/C,SAAS,cAAc,CAA6B,EAAA;AACzD,EAAO,OAAA,CAAA,CAAE,WAAW,MAAM,CAAA,CAAA;AAC5B,CAAA;AAoBO,SAAS,YAAY,KAAgC,EAAA;AAC1D,EAAA,IAAI,OAAO,KAAA,KAAU,QAAY,IAAA,KAAA,IAAS,IAAM,EAAA;AAC9C,IAAO,OAAA,KAAA,CAAA;AAAA,GACT;AAEA,EAAM,MAAA,CAAA,GAAI,MAAO,CAAA,cAAA,CAAe,KAAK,CAAA,CAAA;AACrC,EAAI,IAAA,CAAA,IAAK,QAAQ,OAAO,CAAA,KAAM,YAAY,OAAO,CAAA,CAAE,MAAM,CAAA,KAAM,UAAY,EAAA;AACzE,IAAO,OAAA,KAAA,CAAA;AAAA,GACT;AAEA,EAAA,OAAO,eAAgB,CAAA,QAAA,CAAS,KAAM,CAAA,IAAA,EAAM,CAAA,CAAA;AAC9C,CAAA;AAmBO,SAAS,QACd,KASS,EAAA;AACT,EAAI,IAAA,WAAA,CAAY,KAAK,CAAG,EAAA;AACtB,IAAA,OAAO,MAAM,IAAK,EAAA,CAAA;AAAA,GACpB;AAEA,EAAO,OAAA,MAAA,CAAA;AACT;;;;;;;;;;;;;;;;"}
|
package/dist/loro.mjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"loro.mjs","sources":["../src/index.ts"],"sourcesContent":["export * from \"loro-wasm\";\nimport { Container, Delta, LoroText, LoroTree, OpId, Value, ContainerID, Loro, LoroList, LoroMap, TreeID } from \"loro-wasm\";\n\n\nLoro.prototype.getTypedMap = function (...args) {\n return this.getMap(...args);\n};\nLoro.prototype.getTypedList = function (...args) {\n return this.getList(...args);\n};\nLoroList.prototype.getTyped = function (loro, index) {\n const value = this.get(index);\n if (typeof value === \"string\" && isContainerId(value)) {\n return loro.getContainerById(value);\n } else {\n return value;\n }\n};\nLoroList.prototype.insertTyped = function (...args) {\n return this.insert(...args);\n};\nLoroMap.prototype.getTyped = function (loro, key) {\n const value = this.get(key);\n if (typeof value === \"string\" && isContainerId(value)) {\n return loro.getContainerById(value);\n } else {\n return value;\n }\n};\nLoroMap.prototype.setTyped = function (...args) {\n return this.set(...args);\n};\n\nexport type Frontiers = OpId[];\n\n/**\n * Represents a path to identify the exact location of an event's target.\n * The path is composed of numbers (e.g., indices of a list container)
|
|
1
|
+
{"version":3,"file":"loro.mjs","sources":["../src/index.ts"],"sourcesContent":["export * from \"loro-wasm\";\nimport { Container, Delta, LoroText, LoroTree,LoroTreeNode, OpId, Value, ContainerID, Loro, LoroList, LoroMap, TreeID } from \"loro-wasm\";\n\n\nLoro.prototype.getTypedMap = function (...args) {\n return this.getMap(...args);\n};\nLoro.prototype.getTypedList = function (...args) {\n return this.getList(...args);\n};\nLoroList.prototype.getTyped = function (loro, index) {\n const value = this.get(index);\n if (typeof value === \"string\" && isContainerId(value)) {\n return loro.getContainerById(value);\n } else {\n return value;\n }\n};\nLoroList.prototype.insertTyped = function (...args) {\n return this.insert(...args);\n};\nLoroMap.prototype.getTyped = function (loro, key) {\n const value = this.get(key);\n if (typeof value === \"string\" && isContainerId(value)) {\n return loro.getContainerById(value);\n } else {\n return value;\n }\n};\nLoroMap.prototype.setTyped = function (...args) {\n return this.set(...args);\n};\n\nexport type Frontiers = OpId[];\n\n/**\n * Represents a path to identify the exact location of an event's target.\n * The path is composed of numbers (e.g., indices of a list container) strings\n * (e.g., keys of a map container) and TreeID (the node of a tree container), \n * indicating the absolute position of the event's source within a loro document.\n */\nexport type Path = (number | string | TreeID )[];\n\n/**\n * A batch of events that created by a single `import`/`transaction`/`checkout`.\n *\n * @prop local - Indicates whether the event is local.\n * @prop origin - (Optional) Provides information about the origin of the event.\n * @prop diff - Contains the differential information related to the event.\n * @prop target - Identifies the container ID of the event's target.\n * @prop path - Specifies the absolute path of the event's emitter, which can be an index of a list container or a key of a map container.\n */\nexport interface LoroEventBatch {\n local: boolean;\n /**\n * If true, this event was triggered by a checkout.\n */\n fromCheckout: boolean;\n origin?: string;\n /**\n * The container ID of the current event receiver.\n * It's undefined if the subscriber is on the root document.\n */\n currentTarget?: ContainerID;\n events: LoroEvent[];\n}\n\n/**\n * The concrete event of Loro.\n */\nexport interface LoroEvent {\n /**\n * The container ID of the event's target.\n */\n target: ContainerID;\n diff: Diff;\n /**\n * The absolute path of the event's emitter, which can be an index of a list container or a key of a map container.\n */\n path: Path;\n}\n\nexport type ListDiff = {\n type: \"list\";\n diff: Delta<(Value | Container)[]>[];\n};\n\nexport type TextDiff = {\n type: \"text\";\n diff: Delta<string>[];\n};\n\nexport type MapDiff = {\n type: \"map\";\n updated: Record<string, Value | Container | undefined>;\n};\n\nexport type TreeDiffItem = { target: TreeID; action: \"create\"; parent: TreeID | undefined }\n | { target: TreeID; action: \"delete\" }\n | { target: TreeID; action: \"move\"; parent: TreeID | undefined };\n\nexport type TreeDiff = {\n type: \"tree\";\n diff: TreeDiffItem[];\n};\n\nexport type Diff = ListDiff | TextDiff | MapDiff | TreeDiff;\n\ninterface Listener {\n (event: LoroEventBatch): void;\n}\n\nconst CONTAINER_TYPES = [\"Map\", \"Text\", \"List\", \"Tree\"];\n\nexport function isContainerId(s: string): s is ContainerID {\n return s.startsWith(\"cid:\");\n}\n\nexport { Loro };\n\n/** Whether the value is a container.\n *\n * # Example\n *\n * ```ts\n * const doc = new Loro();\n * const map = doc.getMap(\"map\");\n * const list = doc.getList(\"list\");\n * const text = doc.getText(\"text\");\n * isContainer(map); // true\n * isContainer(list); // true\n * isContainer(text); // true\n * isContainer(123); // false\n * isContainer(\"123\"); // false\n * isContainer({}); // false\n */\nexport function isContainer(value: any): value is Container {\n if (typeof value !== \"object\" || value == null) {\n return false;\n }\n\n const p = Object.getPrototypeOf(value);\n if (p == null || typeof p !== \"object\" || typeof p[\"kind\"] !== \"function\") {\n return false;\n }\n\n return CONTAINER_TYPES.includes(value.kind());\n}\n\n/** Get the type of a value that may be a container.\n *\n * # Example\n *\n * ```ts\n * const doc = new Loro();\n * const map = doc.getMap(\"map\");\n * const list = doc.getList(\"list\");\n * const text = doc.getText(\"text\");\n * getType(map); // \"Map\"\n * getType(list); // \"List\"\n * getType(text); // \"Text\"\n * getType(123); // \"Json\"\n * getType(\"123\"); // \"Json\"\n * getType({}); // \"Json\"\n * ```\n */\nexport function getType<T>(\n value: T,\n): T extends LoroText\n ? \"Text\"\n : T extends LoroMap\n ? \"Map\"\n : T extends LoroTree\n ? \"Tree\"\n : T extends LoroList\n ? \"List\"\n : \"Json\" {\n if (isContainer(value)) {\n return value.kind();\n }\n\n return \"Json\" as any;\n}\n\ndeclare module \"loro-wasm\" {\n interface Loro {\n subscribe(listener: Listener): number;\n }\n\n interface Loro<T extends Record<string, any> = Record<string, any>> {\n getTypedMap<Key extends keyof T & string>(\n name: Key,\n ): T[Key] extends LoroMap ? T[Key] : never;\n getTypedList<Key extends keyof T & string>(\n name: Key,\n ): T[Key] extends LoroList ? T[Key] : never;\n }\n\n interface LoroList<T extends any[] = any[]> {\n insertContainer(pos: number, container: \"Map\"): LoroMap;\n insertContainer(pos: number, container: \"List\"): LoroList;\n insertContainer(pos: number, container: \"Text\"): LoroText;\n insertContainer(pos: number, container: \"Tree\"): LoroTree;\n insertContainer(pos: number, container: string): never;\n\n get(index: number): undefined | Value | Container;\n getTyped<Key extends keyof T & number>(loro: Loro, index: Key): T[Key];\n insertTyped<Key extends keyof T & number>(pos: Key, value: T[Key]): void;\n insert(pos: number, value: Value): void;\n delete(pos: number, len: number): void;\n subscribe(txn: Loro, listener: Listener): number;\n }\n\n interface LoroMap<T extends Record<string, any> = Record<string, any>> {\n setContainer(key: string, container_type: \"Map\"): LoroMap;\n setContainer(key: string, container_type: \"List\"): LoroList;\n setContainer(key: string, container_type: \"Text\"): LoroText;\n setContainer(key: string, container_type: \"Tree\"): LoroTree;\n setContainer(key: string, container_type: string): never;\n\n get(key: string): undefined | Value | Container;\n getTyped<Key extends keyof T & string>(txn: Loro, key: Key): T[Key];\n set(key: string, value: Value): void;\n setTyped<Key extends keyof T & string>(key: Key, value: T[Key]): void;\n delete(key: string): void;\n subscribe(txn: Loro, listener: Listener): number;\n }\n\n interface LoroText {\n insert(pos: number, text: string): void;\n delete(pos: number, len: number): void;\n subscribe(txn: Loro, listener: Listener): number;\n }\n\n interface LoroTree {\n createNode(parent: TreeID | undefined): LoroTreeNode;\n move(target: TreeID, parent: TreeID | undefined): void;\n delete(target: TreeID): void;\n has(target: TreeID): boolean;\n getNodeByID(target: TreeID): LoroTreeNode;\n subscribe(txn: Loro, listener: Listener): number;\n }\n\n interface LoroTreeNode{\n readonly data: LoroMap;\n createNode(): LoroTreeNode;\n setAsRoot(): void;\n moveTo(parent: LoroTreeNode): void;\n parent(): LoroTreeNode | undefined;\n children(): Array<LoroTreeNode>;\n }\n}\n"],"names":[],"mappings":";;;;AAIA,IAAK,CAAA,SAAA,CAAU,WAAc,GAAA,SAAA,GAAa,IAAM,EAAA;AAC9C,EAAO,OAAA,IAAA,CAAK,MAAO,CAAA,GAAG,IAAI,CAAA,CAAA;AAC5B,CAAA,CAAA;AACA,IAAK,CAAA,SAAA,CAAU,YAAe,GAAA,SAAA,GAAa,IAAM,EAAA;AAC/C,EAAO,OAAA,IAAA,CAAK,OAAQ,CAAA,GAAG,IAAI,CAAA,CAAA;AAC7B,CAAA,CAAA;AACA,QAAA,CAAS,SAAU,CAAA,QAAA,GAAW,SAAU,IAAA,EAAM,KAAO,EAAA;AACnD,EAAM,MAAA,KAAA,GAAQ,IAAK,CAAA,GAAA,CAAI,KAAK,CAAA,CAAA;AAC5B,EAAA,IAAI,OAAO,KAAA,KAAU,QAAY,IAAA,aAAA,CAAc,KAAK,CAAG,EAAA;AACrD,IAAO,OAAA,IAAA,CAAK,iBAAiB,KAAK,CAAA,CAAA;AAAA,GAC7B,MAAA;AACL,IAAO,OAAA,KAAA,CAAA;AAAA,GACT;AACF,CAAA,CAAA;AACA,QAAS,CAAA,SAAA,CAAU,WAAc,GAAA,SAAA,GAAa,IAAM,EAAA;AAClD,EAAO,OAAA,IAAA,CAAK,MAAO,CAAA,GAAG,IAAI,CAAA,CAAA;AAC5B,CAAA,CAAA;AACA,OAAA,CAAQ,SAAU,CAAA,QAAA,GAAW,SAAU,IAAA,EAAM,GAAK,EAAA;AAChD,EAAM,MAAA,KAAA,GAAQ,IAAK,CAAA,GAAA,CAAI,GAAG,CAAA,CAAA;AAC1B,EAAA,IAAI,OAAO,KAAA,KAAU,QAAY,IAAA,aAAA,CAAc,KAAK,CAAG,EAAA;AACrD,IAAO,OAAA,IAAA,CAAK,iBAAiB,KAAK,CAAA,CAAA;AAAA,GAC7B,MAAA;AACL,IAAO,OAAA,KAAA,CAAA;AAAA,GACT;AACF,CAAA,CAAA;AACA,OAAQ,CAAA,SAAA,CAAU,QAAW,GAAA,SAAA,GAAa,IAAM,EAAA;AAC9C,EAAO,OAAA,IAAA,CAAK,GAAI,CAAA,GAAG,IAAI,CAAA,CAAA;AACzB,CAAA,CAAA;AAiFA,MAAM,eAAkB,GAAA,CAAC,KAAO,EAAA,MAAA,EAAQ,QAAQ,MAAM,CAAA,CAAA;AAE/C,SAAS,cAAc,CAA6B,EAAA;AACzD,EAAO,OAAA,CAAA,CAAE,WAAW,MAAM,CAAA,CAAA;AAC5B,CAAA;AAoBO,SAAS,YAAY,KAAgC,EAAA;AAC1D,EAAA,IAAI,OAAO,KAAA,KAAU,QAAY,IAAA,KAAA,IAAS,IAAM,EAAA;AAC9C,IAAO,OAAA,KAAA,CAAA;AAAA,GACT;AAEA,EAAM,MAAA,CAAA,GAAI,MAAO,CAAA,cAAA,CAAe,KAAK,CAAA,CAAA;AACrC,EAAI,IAAA,CAAA,IAAK,QAAQ,OAAO,CAAA,KAAM,YAAY,OAAO,CAAA,CAAE,MAAM,CAAA,KAAM,UAAY,EAAA;AACzE,IAAO,OAAA,KAAA,CAAA;AAAA,GACT;AAEA,EAAA,OAAO,eAAgB,CAAA,QAAA,CAAS,KAAM,CAAA,IAAA,EAAM,CAAA,CAAA;AAC9C,CAAA;AAmBO,SAAS,QACd,KASS,EAAA;AACT,EAAI,IAAA,WAAA,CAAY,KAAK,CAAG,EAAA;AACtB,IAAA,OAAO,MAAM,IAAK,EAAA,CAAA;AAAA,GACpB;AAEA,EAAO,OAAA,MAAA,CAAA;AACT;;;;"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "loro-crdt",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.11.0",
|
|
4
4
|
"description": "Loro CRDTs is a high-performance CRDT framework that makes your app state synchronized, collaborative and maintainable effortlessly.",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"crdt",
|
|
@@ -17,7 +17,7 @@
|
|
|
17
17
|
"homepage": "https://loro.dev",
|
|
18
18
|
"license": "MIT",
|
|
19
19
|
"dependencies": {
|
|
20
|
-
"loro-wasm": "0.
|
|
20
|
+
"loro-wasm": "0.11.0"
|
|
21
21
|
},
|
|
22
22
|
"devDependencies": {
|
|
23
23
|
"@rollup/plugin-node-resolve": "^15.0.1",
|
package/src/index.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
export * from "loro-wasm";
|
|
2
|
-
import { Container, Delta, LoroText, LoroTree, OpId, Value, ContainerID, Loro, LoroList, LoroMap, TreeID } from "loro-wasm";
|
|
2
|
+
import { Container, Delta, LoroText, LoroTree,LoroTreeNode, OpId, Value, ContainerID, Loro, LoroList, LoroMap, TreeID } from "loro-wasm";
|
|
3
3
|
|
|
4
4
|
|
|
5
5
|
Loro.prototype.getTypedMap = function (...args) {
|
|
@@ -35,37 +35,48 @@ export type Frontiers = OpId[];
|
|
|
35
35
|
|
|
36
36
|
/**
|
|
37
37
|
* Represents a path to identify the exact location of an event's target.
|
|
38
|
-
* The path is composed of numbers (e.g., indices of a list container)
|
|
39
|
-
* (e.g., keys of a map container)
|
|
40
|
-
* within a loro document.
|
|
38
|
+
* The path is composed of numbers (e.g., indices of a list container) strings
|
|
39
|
+
* (e.g., keys of a map container) and TreeID (the node of a tree container),
|
|
40
|
+
* indicating the absolute position of the event's source within a loro document.
|
|
41
41
|
*/
|
|
42
|
-
export type Path = (number | string)[];
|
|
42
|
+
export type Path = (number | string | TreeID )[];
|
|
43
43
|
|
|
44
44
|
/**
|
|
45
|
-
*
|
|
45
|
+
* A batch of events that created by a single `import`/`transaction`/`checkout`.
|
|
46
|
+
*
|
|
46
47
|
* @prop local - Indicates whether the event is local.
|
|
47
48
|
* @prop origin - (Optional) Provides information about the origin of the event.
|
|
48
49
|
* @prop diff - Contains the differential information related to the event.
|
|
49
50
|
* @prop target - Identifies the container ID of the event's target.
|
|
50
51
|
* @prop path - Specifies the absolute path of the event's emitter, which can be an index of a list container or a key of a map container.
|
|
51
52
|
*/
|
|
52
|
-
export interface
|
|
53
|
+
export interface LoroEventBatch {
|
|
54
|
+
local: boolean;
|
|
53
55
|
/**
|
|
54
|
-
*
|
|
56
|
+
* If true, this event was triggered by a checkout.
|
|
55
57
|
*/
|
|
56
|
-
|
|
57
|
-
local: boolean;
|
|
58
|
+
fromCheckout: boolean;
|
|
58
59
|
origin?: string;
|
|
59
60
|
/**
|
|
60
|
-
*
|
|
61
|
+
* The container ID of the current event receiver.
|
|
62
|
+
* It's undefined if the subscriber is on the root document.
|
|
61
63
|
*/
|
|
62
|
-
|
|
64
|
+
currentTarget?: ContainerID;
|
|
65
|
+
events: LoroEvent[];
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
/**
|
|
69
|
+
* The concrete event of Loro.
|
|
70
|
+
*/
|
|
71
|
+
export interface LoroEvent {
|
|
63
72
|
/**
|
|
64
|
-
*
|
|
73
|
+
* The container ID of the event's target.
|
|
65
74
|
*/
|
|
66
|
-
fromCheckout: boolean;
|
|
67
|
-
diff: Diff;
|
|
68
75
|
target: ContainerID;
|
|
76
|
+
diff: Diff;
|
|
77
|
+
/**
|
|
78
|
+
* The absolute path of the event's emitter, which can be an index of a list container or a key of a map container.
|
|
79
|
+
*/
|
|
69
80
|
path: Path;
|
|
70
81
|
}
|
|
71
82
|
|
|
@@ -84,17 +95,19 @@ export type MapDiff = {
|
|
|
84
95
|
updated: Record<string, Value | Container | undefined>;
|
|
85
96
|
};
|
|
86
97
|
|
|
98
|
+
export type TreeDiffItem = { target: TreeID; action: "create"; parent: TreeID | undefined }
|
|
99
|
+
| { target: TreeID; action: "delete" }
|
|
100
|
+
| { target: TreeID; action: "move"; parent: TreeID | undefined };
|
|
101
|
+
|
|
87
102
|
export type TreeDiff = {
|
|
88
103
|
type: "tree";
|
|
89
|
-
diff:
|
|
90
|
-
| { target: TreeID; action: "create" | "delete" }
|
|
91
|
-
| { target: TreeID; action: "move"; parent: TreeID };
|
|
104
|
+
diff: TreeDiffItem[];
|
|
92
105
|
};
|
|
93
106
|
|
|
94
107
|
export type Diff = ListDiff | TextDiff | MapDiff | TreeDiff;
|
|
95
108
|
|
|
96
109
|
interface Listener {
|
|
97
|
-
(event:
|
|
110
|
+
(event: LoroEventBatch): void;
|
|
98
111
|
}
|
|
99
112
|
|
|
100
113
|
const CONTAINER_TYPES = ["Map", "Text", "List", "Tree"];
|
|
@@ -106,9 +119,9 @@ export function isContainerId(s: string): s is ContainerID {
|
|
|
106
119
|
export { Loro };
|
|
107
120
|
|
|
108
121
|
/** Whether the value is a container.
|
|
109
|
-
*
|
|
122
|
+
*
|
|
110
123
|
* # Example
|
|
111
|
-
*
|
|
124
|
+
*
|
|
112
125
|
* ```ts
|
|
113
126
|
* const doc = new Loro();
|
|
114
127
|
* const map = doc.getMap("map");
|
|
@@ -135,9 +148,9 @@ export function isContainer(value: any): value is Container {
|
|
|
135
148
|
}
|
|
136
149
|
|
|
137
150
|
/** Get the type of a value that may be a container.
|
|
138
|
-
*
|
|
151
|
+
*
|
|
139
152
|
* # Example
|
|
140
|
-
*
|
|
153
|
+
*
|
|
141
154
|
* ```ts
|
|
142
155
|
* const doc = new Loro();
|
|
143
156
|
* const map = doc.getMap("map");
|
|
@@ -151,10 +164,17 @@ export function isContainer(value: any): value is Container {
|
|
|
151
164
|
* getType({}); // "Json"
|
|
152
165
|
* ```
|
|
153
166
|
*/
|
|
154
|
-
export function getType<T>(
|
|
155
|
-
T
|
|
156
|
-
|
|
157
|
-
|
|
167
|
+
export function getType<T>(
|
|
168
|
+
value: T,
|
|
169
|
+
): T extends LoroText
|
|
170
|
+
? "Text"
|
|
171
|
+
: T extends LoroMap
|
|
172
|
+
? "Map"
|
|
173
|
+
: T extends LoroTree
|
|
174
|
+
? "Tree"
|
|
175
|
+
: T extends LoroList
|
|
176
|
+
? "List"
|
|
177
|
+
: "Json" {
|
|
158
178
|
if (isContainer(value)) {
|
|
159
179
|
return value.kind();
|
|
160
180
|
}
|
|
@@ -169,10 +189,10 @@ declare module "loro-wasm" {
|
|
|
169
189
|
|
|
170
190
|
interface Loro<T extends Record<string, any> = Record<string, any>> {
|
|
171
191
|
getTypedMap<Key extends keyof T & string>(
|
|
172
|
-
name: Key
|
|
192
|
+
name: Key,
|
|
173
193
|
): T[Key] extends LoroMap ? T[Key] : never;
|
|
174
194
|
getTypedList<Key extends keyof T & string>(
|
|
175
|
-
name: Key
|
|
195
|
+
name: Key,
|
|
176
196
|
): T[Key] extends LoroList ? T[Key] : never;
|
|
177
197
|
}
|
|
178
198
|
|
|
@@ -213,12 +233,20 @@ declare module "loro-wasm" {
|
|
|
213
233
|
}
|
|
214
234
|
|
|
215
235
|
interface LoroTree {
|
|
216
|
-
|
|
217
|
-
|
|
236
|
+
createNode(parent: TreeID | undefined): LoroTreeNode;
|
|
237
|
+
move(target: TreeID, parent: TreeID | undefined): void;
|
|
218
238
|
delete(target: TreeID): void;
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
contains(target: TreeID): boolean;
|
|
239
|
+
has(target: TreeID): boolean;
|
|
240
|
+
getNodeByID(target: TreeID): LoroTreeNode;
|
|
222
241
|
subscribe(txn: Loro, listener: Listener): number;
|
|
223
242
|
}
|
|
243
|
+
|
|
244
|
+
interface LoroTreeNode{
|
|
245
|
+
readonly data: LoroMap;
|
|
246
|
+
createNode(): LoroTreeNode;
|
|
247
|
+
setAsRoot(): void;
|
|
248
|
+
moveTo(parent: LoroTreeNode): void;
|
|
249
|
+
parent(): LoroTreeNode | undefined;
|
|
250
|
+
children(): Array<LoroTreeNode>;
|
|
251
|
+
}
|
|
224
252
|
}
|