@liveblocks/client 0.13.0-beta.1 → 0.14.0-beta.1

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 CHANGED
@@ -8,17 +8,17 @@
8
8
 
9
9
  **At [Liveblocks](https://liveblocks.io), we’re building tools to help companies create world-class collaborative products that attract, engage and retain users.** This repository is a set of open-source packages for building performant and reliable multiplayer experiences.
10
10
 
11
+ ## Installation
12
+
13
+ ```
14
+ npm install @liveblocks/client
15
+ ```
16
+
11
17
  ## Examples
12
18
 
13
19
  - Browse our gallery of collaborative UI patterns. [View examples gallery](https://liveblocks.io/examples)
14
20
  - Explore and clone any of our open-source examples. [View code examples](https://github.com/liveblocks/liveblocks/tree/main/examples)
15
21
 
16
- ## Packages
17
-
18
- - [@liveblocks/client](https://github.com/liveblocks/liveblocks/tree/main/packages/liveblocks)
19
- - [@liveblocks/react](https://github.com/liveblocks/liveblocks/tree/main/packages/liveblocks-react)
20
- - [@liveblocks/node](https://github.com/liveblocks/liveblocks/tree/main/packages/liveblocks-node)
21
-
22
22
  ## Documentation
23
23
 
24
24
  [Read the documentation](https://liveblocks.io/docs) to start using Liveblocks.
@@ -35,11 +35,11 @@ For changelog, visit [https://github.com/liveblocks/liveblocks/releases](https:/
35
35
 
36
36
  ## Community
37
37
 
38
- - [Slack](https://join.slack.com/t/liveblocks-community/shared_invite/zt-qozwnk75-6RB0i1wk1lx470KX0YuZxQ) - To get involved with the Liveblocks community, ask questions and share tips.
38
+ - [Discord](https://discord.gg/X4YWJuH9VY) - To get involved with the Liveblocks community, ask questions and share tips.
39
39
  - [Twitter](https://twitter.com/liveblocks) - To receive updates, announcements, blog posts, and general Liveblocks tips.
40
40
 
41
41
  ## License
42
42
 
43
43
  Licensed under the Apache License 2.0, Copyright © 2021-present [Liveblocks](https://liveblocks.io).
44
44
 
45
- See [LICENSE](./LICENSE) for more information.
45
+ See [LICENSE](../../LICENSE) for more information.
@@ -1,4 +1,4 @@
1
- import { Op } from "./live";
1
+ import { Op, SerializedCrdt } from "./live";
2
2
  export declare type ApplyResult = {
3
3
  reverse: Op[];
4
4
  modified: AbstractCrdt;
@@ -33,7 +33,7 @@ export declare abstract class AbstractCrdt {
33
33
  /**
34
34
  * INTERNAL
35
35
  */
36
- _apply(op: Op): ApplyResult;
36
+ _apply(op: Op, isLocal: boolean): ApplyResult;
37
37
  /**
38
38
  * INTERNAL
39
39
  */
@@ -45,7 +45,7 @@ export declare abstract class AbstractCrdt {
45
45
  /**
46
46
  * INTERNAL
47
47
  */
48
- abstract _attachChild(id: string, key: string, crdt: AbstractCrdt): ApplyResult;
48
+ abstract _attachChild(id: string, key: string, crdt: AbstractCrdt, isLocal: boolean): ApplyResult;
49
49
  /**
50
50
  * INTERNAL
51
51
  */
@@ -57,5 +57,9 @@ export declare abstract class AbstractCrdt {
57
57
  /**
58
58
  * INTERNAL
59
59
  */
60
- abstract _serialize(parentId: string, parentKey: string): Op[];
60
+ abstract _serialize(parentId: string, parentKey: string, doc?: Doc): Op[];
61
+ /**
62
+ * INTERNAL
63
+ */
64
+ abstract _toSerializedCrdt(): SerializedCrdt;
61
65
  }
@@ -48,12 +48,12 @@ class AbstractCrdt {
48
48
  /**
49
49
  * INTERNAL
50
50
  */
51
- _apply(op) {
51
+ _apply(op, isLocal) {
52
52
  switch (op.type) {
53
53
  case live_1.OpType.DeleteCrdt: {
54
54
  if (this._parent != null && this._parentKey != null) {
55
55
  const parent = this._parent;
56
- const reverse = this._serialize(this._parent._id, this._parentKey);
56
+ const reverse = this._serialize(this._parent._id, this._parentKey, __classPrivateFieldGet(this, _AbstractCrdt_doc, "f"));
57
57
  this._parent._detachChild(this);
58
58
  return { modified: parent, reverse };
59
59
  }
@@ -1,5 +1,5 @@
1
1
  import { AbstractCrdt, Doc, ApplyResult } from "./AbstractCrdt";
2
- import { SerializedList, SerializedCrdtWithId, Op } from "./live";
2
+ import { SerializedList, SerializedCrdtWithId, Op, SerializedCrdt } from "./live";
3
3
  /**
4
4
  * The LiveList class represents an ordered collection of items that is synchorinized across clients.
5
5
  */
@@ -13,7 +13,7 @@ export declare class LiveList<T> extends AbstractCrdt {
13
13
  /**
14
14
  * INTERNAL
15
15
  */
16
- _serialize(parentId?: string, parentKey?: string): Op[];
16
+ _serialize(parentId?: string, parentKey?: string, doc?: Doc): Op[];
17
17
  /**
18
18
  * INTERNAL
19
19
  */
@@ -25,7 +25,7 @@ export declare class LiveList<T> extends AbstractCrdt {
25
25
  /**
26
26
  * INTERNAL
27
27
  */
28
- _attachChild(id: string, key: string, child: AbstractCrdt): ApplyResult;
28
+ _attachChild(id: string, key: string, child: AbstractCrdt, isLocal: boolean): ApplyResult;
29
29
  /**
30
30
  * INTERNAL
31
31
  */
@@ -37,7 +37,11 @@ export declare class LiveList<T> extends AbstractCrdt {
37
37
  /**
38
38
  * INTERNAL
39
39
  */
40
- _apply(op: Op): ApplyResult;
40
+ _apply(op: Op, isLocal: boolean): ApplyResult;
41
+ /**
42
+ * INTERNAL
43
+ */
44
+ _toSerializedCrdt(): SerializedCrdt;
41
45
  /**
42
46
  * Returns the number of elements.
43
47
  */
@@ -54,7 +54,7 @@ class LiveList extends AbstractCrdt_1.AbstractCrdt {
54
54
  /**
55
55
  * INTERNAL
56
56
  */
57
- _serialize(parentId, parentKey) {
57
+ _serialize(parentId, parentKey, doc) {
58
58
  if (this._id == null) {
59
59
  throw new Error("Cannot serialize item is not attached");
60
60
  }
@@ -64,13 +64,14 @@ class LiveList extends AbstractCrdt_1.AbstractCrdt {
64
64
  const ops = [];
65
65
  const op = {
66
66
  id: this._id,
67
+ opId: doc === null || doc === void 0 ? void 0 : doc.generateOpId(),
67
68
  type: live_1.OpType.CreateList,
68
69
  parentId,
69
70
  parentKey,
70
71
  };
71
72
  ops.push(op);
72
73
  for (const [value, key] of __classPrivateFieldGet(this, _LiveList_items, "f")) {
73
- ops.push(...value._serialize(this._id, key));
74
+ ops.push(...value._serialize(this._id, key, doc));
74
75
  }
75
76
  return ops;
76
77
  }
@@ -95,7 +96,7 @@ class LiveList extends AbstractCrdt_1.AbstractCrdt {
95
96
  /**
96
97
  * INTERNAL
97
98
  */
98
- _attachChild(id, key, child) {
99
+ _attachChild(id, key, child, isLocal) {
99
100
  var _a;
100
101
  if (this._doc == null) {
101
102
  throw new Error("Can't attach child if doc is not present");
@@ -103,11 +104,24 @@ class LiveList extends AbstractCrdt_1.AbstractCrdt {
103
104
  child._attach(id, this._doc);
104
105
  child._setParentLink(this, key);
105
106
  const index = __classPrivateFieldGet(this, _LiveList_items, "f").findIndex((entry) => entry[1] === key);
106
- // Assign a temporary position until we get the fix from the backend
107
+ let newKey = key;
108
+ // If there is a conflict
107
109
  if (index !== -1) {
108
- __classPrivateFieldGet(this, _LiveList_items, "f")[index][1] = (0, position_1.makePosition)(key, (_a = __classPrivateFieldGet(this, _LiveList_items, "f")[index + 1]) === null || _a === void 0 ? void 0 : _a[1]);
110
+ if (isLocal) {
111
+ // If change is local => assign a temporary position to newly attached child
112
+ let before = __classPrivateFieldGet(this, _LiveList_items, "f")[index] ? __classPrivateFieldGet(this, _LiveList_items, "f")[index][1] : undefined;
113
+ let after = __classPrivateFieldGet(this, _LiveList_items, "f")[index + 1]
114
+ ? __classPrivateFieldGet(this, _LiveList_items, "f")[index + 1][1]
115
+ : undefined;
116
+ newKey = (0, position_1.makePosition)(before, after);
117
+ child._setParentLink(this, newKey);
118
+ }
119
+ else {
120
+ // If change is remote => assign a temporary position to existing child until we get the fix from the backend
121
+ __classPrivateFieldGet(this, _LiveList_items, "f")[index][1] = (0, position_1.makePosition)(key, (_a = __classPrivateFieldGet(this, _LiveList_items, "f")[index + 1]) === null || _a === void 0 ? void 0 : _a[1]);
122
+ }
109
123
  }
110
- __classPrivateFieldGet(this, _LiveList_items, "f").push([child, key]);
124
+ __classPrivateFieldGet(this, _LiveList_items, "f").push([child, newKey]);
111
125
  __classPrivateFieldGet(this, _LiveList_items, "f").sort((itemA, itemB) => (0, position_1.compare)(itemA[1], itemB[1]));
112
126
  return { reverse: [{ type: live_1.OpType.DeleteCrdt, id }], modified: this };
113
127
  }
@@ -141,8 +155,19 @@ class LiveList extends AbstractCrdt_1.AbstractCrdt {
141
155
  /**
142
156
  * INTERNAL
143
157
  */
144
- _apply(op) {
145
- return super._apply(op);
158
+ _apply(op, isLocal) {
159
+ return super._apply(op, isLocal);
160
+ }
161
+ /**
162
+ * INTERNAL
163
+ */
164
+ _toSerializedCrdt() {
165
+ var _a;
166
+ return {
167
+ type: live_1.CrdtType.List,
168
+ parentId: (_a = this._parent) === null || _a === void 0 ? void 0 : _a._id,
169
+ parentKey: this._parentKey,
170
+ };
146
171
  }
147
172
  /**
148
173
  * Returns the number of elements.
@@ -176,7 +201,7 @@ class LiveList extends AbstractCrdt_1.AbstractCrdt {
176
201
  if (this._doc && this._id) {
177
202
  const id = this._doc.generateId();
178
203
  value._attach(id, this._doc);
179
- this._doc.dispatch(value._serialize(this._id, position), [{ type: live_1.OpType.DeleteCrdt, id }], [this]);
204
+ this._doc.dispatch(value._serialize(this._id, position, this._doc), [{ type: live_1.OpType.DeleteCrdt, id }], [this]);
180
205
  }
181
206
  }
182
207
  /**
@@ -222,6 +247,7 @@ class LiveList extends AbstractCrdt_1.AbstractCrdt {
222
247
  {
223
248
  type: live_1.OpType.SetParentKey,
224
249
  id: item[0]._id,
250
+ opId: this._doc.generateOpId(),
225
251
  parentKey: position,
226
252
  },
227
253
  ], [
@@ -250,6 +276,7 @@ class LiveList extends AbstractCrdt_1.AbstractCrdt {
250
276
  this._doc.dispatch([
251
277
  {
252
278
  id: childRecordId,
279
+ opId: this._doc.generateOpId(),
253
280
  type: live_1.OpType.DeleteCrdt,
254
281
  },
255
282
  ], item[0]._serialize(this._id, item[1]), [this]);
@@ -1,5 +1,5 @@
1
1
  import { AbstractCrdt, Doc, ApplyResult } from "./AbstractCrdt";
2
- import { Op, SerializedCrdtWithId } from "./live";
2
+ import { Op, SerializedCrdtWithId, SerializedCrdt } from "./live";
3
3
  /**
4
4
  * The LiveMap class is similar to a JavaScript Map that is synchronized on all clients.
5
5
  * Keys should be a string, and values should be serializable to JSON.
@@ -11,7 +11,7 @@ export declare class LiveMap<TKey extends string, TValue> extends AbstractCrdt {
11
11
  /**
12
12
  * INTERNAL
13
13
  */
14
- _serialize(parentId?: string, parentKey?: string): Op[];
14
+ _serialize(parentId?: string, parentKey?: string, doc?: Doc): Op[];
15
15
  /**
16
16
  * INTERNAL
17
17
  */
@@ -23,7 +23,7 @@ export declare class LiveMap<TKey extends string, TValue> extends AbstractCrdt {
23
23
  /**
24
24
  * INTERNAL
25
25
  */
26
- _attachChild(id: string, key: TKey, child: AbstractCrdt): ApplyResult;
26
+ _attachChild(id: string, key: TKey, child: AbstractCrdt, isLocal: boolean): ApplyResult;
27
27
  /**
28
28
  * INTERNAL
29
29
  */
@@ -32,6 +32,10 @@ export declare class LiveMap<TKey extends string, TValue> extends AbstractCrdt {
32
32
  * INTERNAL
33
33
  */
34
34
  _detachChild(child: AbstractCrdt): void;
35
+ /**
36
+ * INTERNAL
37
+ */
38
+ _toSerializedCrdt(): SerializedCrdt;
35
39
  /**
36
40
  * Returns a specified element from the LiveMap.
37
41
  * @param key The key of the element to return.
@@ -41,7 +41,7 @@ class LiveMap extends AbstractCrdt_1.AbstractCrdt {
41
41
  /**
42
42
  * INTERNAL
43
43
  */
44
- _serialize(parentId, parentKey) {
44
+ _serialize(parentId, parentKey, doc) {
45
45
  if (this._id == null) {
46
46
  throw new Error("Cannot serialize item is not attached");
47
47
  }
@@ -51,13 +51,14 @@ class LiveMap extends AbstractCrdt_1.AbstractCrdt {
51
51
  const ops = [];
52
52
  const op = {
53
53
  id: this._id,
54
+ opId: doc === null || doc === void 0 ? void 0 : doc.generateOpId(),
54
55
  type: live_1.OpType.CreateMap,
55
56
  parentId,
56
57
  parentKey,
57
58
  };
58
59
  ops.push(op);
59
60
  for (const [key, value] of __classPrivateFieldGet(this, _LiveMap_map, "f")) {
60
- ops.push(...value._serialize(this._id, key));
61
+ ops.push(...value._serialize(this._id, key, doc));
61
62
  }
62
63
  return ops;
63
64
  }
@@ -99,7 +100,7 @@ class LiveMap extends AbstractCrdt_1.AbstractCrdt {
99
100
  /**
100
101
  * INTERNAL
101
102
  */
102
- _attachChild(id, key, child) {
103
+ _attachChild(id, key, child, isLocal) {
103
104
  if (this._doc == null) {
104
105
  throw new Error("Can't attach child if doc is not present");
105
106
  }
@@ -137,6 +138,17 @@ class LiveMap extends AbstractCrdt_1.AbstractCrdt {
137
138
  }
138
139
  child._detach();
139
140
  }
141
+ /**
142
+ * INTERNAL
143
+ */
144
+ _toSerializedCrdt() {
145
+ var _a;
146
+ return {
147
+ type: live_1.CrdtType.Map,
148
+ parentId: (_a = this._parent) === null || _a === void 0 ? void 0 : _a._id,
149
+ parentKey: this._parentKey,
150
+ };
151
+ }
140
152
  /**
141
153
  * Returns a specified element from the LiveMap.
142
154
  * @param key The key of the element to return.
@@ -165,7 +177,7 @@ class LiveMap extends AbstractCrdt_1.AbstractCrdt {
165
177
  if (this._doc && this._id) {
166
178
  const id = this._doc.generateId();
167
179
  item._attach(id, this._doc);
168
- this._doc.dispatch(item._serialize(this._id, key), oldValue
180
+ this._doc.dispatch(item._serialize(this._id, key, this._doc), oldValue
169
181
  ? oldValue._serialize(this._id, key)
170
182
  : [{ type: live_1.OpType.DeleteCrdt, id }], [this]);
171
183
  }
@@ -195,7 +207,13 @@ class LiveMap extends AbstractCrdt_1.AbstractCrdt {
195
207
  }
196
208
  item._detach();
197
209
  if (this._doc && item._id) {
198
- this._doc.dispatch([{ type: live_1.OpType.DeleteCrdt, id: item._id }], item._serialize(this._id, key), [this]);
210
+ this._doc.dispatch([
211
+ {
212
+ type: live_1.OpType.DeleteCrdt,
213
+ id: item._id,
214
+ opId: this._doc.generateOpId(),
215
+ },
216
+ ], item._serialize(this._id, key), [this]);
199
217
  }
200
218
  __classPrivateFieldGet(this, _LiveMap_map, "f").delete(key);
201
219
  return true;
@@ -1,5 +1,5 @@
1
1
  import { AbstractCrdt, Doc, ApplyResult } from "./AbstractCrdt";
2
- import { Op, SerializedCrdtWithId } from "./live";
2
+ import { Op, SerializedCrdt, SerializedCrdtWithId } from "./live";
3
3
  /**
4
4
  * The LiveObject class is similar to a JavaScript object that is synchronized on all clients.
5
5
  * Keys should be a string, and values should be serializable to JSON.
@@ -11,13 +11,15 @@ export declare class LiveObject<T extends Record<string, any> = Record<string, a
11
11
  /**
12
12
  * INTERNAL
13
13
  */
14
- _serialize(parentId?: string, parentKey?: string): Op[];
14
+ _serialize(parentId?: string, parentKey?: string, doc?: Doc): Op[];
15
15
  /**
16
16
  * INTERNAL
17
17
  */
18
- static _deserialize([id, item]: SerializedCrdtWithId, parentToChildren: Map<string, SerializedCrdtWithId[]>, doc: Doc): LiveObject<{
19
- [key: string]: any;
20
- }>;
18
+ static _deserialize([id, item]: SerializedCrdtWithId, parentToChildren: Map<string, SerializedCrdtWithId[]>, doc: Doc): LiveObject<Record<string, any>>;
19
+ /**
20
+ * INTERNAL
21
+ */
22
+ static _deserializeChildren(object: LiveObject, parentToChildren: Map<string, SerializedCrdtWithId[]>, doc: Doc): LiveObject<Record<string, any>>;
21
23
  /**
22
24
  * INTERNAL
23
25
  */
@@ -25,11 +27,15 @@ export declare class LiveObject<T extends Record<string, any> = Record<string, a
25
27
  /**
26
28
  * INTERNAL
27
29
  */
28
- _attachChild(id: string, key: keyof T, child: AbstractCrdt): ApplyResult;
30
+ _attachChild(id: string, key: keyof T, child: AbstractCrdt, isLocal: boolean): ApplyResult;
29
31
  /**
30
32
  * INTERNAL
31
33
  */
32
34
  _detachChild(child: AbstractCrdt): void;
35
+ /**
36
+ * INTERNAL
37
+ */
38
+ _detachChildren(): void;
33
39
  /**
34
40
  * INTERNAL
35
41
  */
@@ -37,7 +43,11 @@ export declare class LiveObject<T extends Record<string, any> = Record<string, a
37
43
  /**
38
44
  * INTERNAL
39
45
  */
40
- _apply(op: Op): ApplyResult;
46
+ _apply(op: Op, isLocal: boolean): ApplyResult;
47
+ /**
48
+ * INTERNAL
49
+ */
50
+ _toSerializedCrdt(): SerializedCrdt;
41
51
  /**
42
52
  * Transform the LiveObject into a javascript object
43
53
  */
@@ -53,6 +63,11 @@ export declare class LiveObject<T extends Record<string, any> = Record<string, a
53
63
  * @param key The key of the property to get
54
64
  */
55
65
  get<TKey extends keyof T>(key: TKey): T[TKey];
66
+ /**
67
+ * Deletes a key from the LiveObject
68
+ * @param key The key of the property to delete
69
+ */
70
+ delete(key: keyof T): void;
56
71
  /**
57
72
  * Adds or updates multiple properties at once with an object.
58
73
  * @param overrides The object used to overrides properties
@@ -38,13 +38,14 @@ class LiveObject extends AbstractCrdt_1.AbstractCrdt {
38
38
  /**
39
39
  * INTERNAL
40
40
  */
41
- _serialize(parentId, parentKey) {
41
+ _serialize(parentId, parentKey, doc) {
42
42
  if (this._id == null) {
43
43
  throw new Error("Cannot serialize item is not attached");
44
44
  }
45
45
  const ops = [];
46
46
  const op = {
47
47
  id: this._id,
48
+ opId: doc === null || doc === void 0 ? void 0 : doc.generateOpId(),
48
49
  type: live_1.OpType.CreateObject,
49
50
  parentId,
50
51
  parentKey,
@@ -53,7 +54,7 @@ class LiveObject extends AbstractCrdt_1.AbstractCrdt {
53
54
  ops.push(op);
54
55
  for (const [key, value] of __classPrivateFieldGet(this, _LiveObject_map, "f")) {
55
56
  if (value instanceof AbstractCrdt_1.AbstractCrdt) {
56
- ops.push(...value._serialize(this._id, key));
57
+ ops.push(...value._serialize(this._id, key, doc));
57
58
  }
58
59
  else {
59
60
  op.data[key] = value;
@@ -70,7 +71,13 @@ class LiveObject extends AbstractCrdt_1.AbstractCrdt {
70
71
  }
71
72
  const object = new LiveObject(item.data);
72
73
  object._attach(id, doc);
73
- const children = parentToChildren.get(id);
74
+ return this._deserializeChildren(object, parentToChildren, doc);
75
+ }
76
+ /**
77
+ * INTERNAL
78
+ */
79
+ static _deserializeChildren(object, parentToChildren, doc) {
80
+ const children = parentToChildren.get(object._id);
74
81
  if (children == null) {
75
82
  return object;
76
83
  }
@@ -99,7 +106,7 @@ class LiveObject extends AbstractCrdt_1.AbstractCrdt {
99
106
  /**
100
107
  * INTERNAL
101
108
  */
102
- _attachChild(id, key, child) {
109
+ _attachChild(id, key, child, isLocal) {
103
110
  if (this._doc == null) {
104
111
  throw new Error("Can't attach child if doc is not present");
105
112
  }
@@ -141,6 +148,15 @@ class LiveObject extends AbstractCrdt_1.AbstractCrdt {
141
148
  child._detach();
142
149
  }
143
150
  }
151
+ /**
152
+ * INTERNAL
153
+ */
154
+ _detachChildren() {
155
+ for (const [key, value] of __classPrivateFieldGet(this, _LiveObject_map, "f")) {
156
+ __classPrivateFieldGet(this, _LiveObject_map, "f").delete(key);
157
+ value._detach();
158
+ }
159
+ }
144
160
  /**
145
161
  * INTERNAL
146
162
  */
@@ -155,14 +171,26 @@ class LiveObject extends AbstractCrdt_1.AbstractCrdt {
155
171
  /**
156
172
  * INTERNAL
157
173
  */
158
- _apply(op) {
174
+ _apply(op, isLocal) {
159
175
  if (op.type === live_1.OpType.UpdateObject) {
160
- return __classPrivateFieldGet(this, _LiveObject_instances, "m", _LiveObject_applyUpdate).call(this, op);
176
+ return __classPrivateFieldGet(this, _LiveObject_instances, "m", _LiveObject_applyUpdate).call(this, op, isLocal);
161
177
  }
162
178
  else if (op.type === live_1.OpType.DeleteObjectKey) {
163
179
  return __classPrivateFieldGet(this, _LiveObject_instances, "m", _LiveObject_applyDeleteObjectKey).call(this, op);
164
180
  }
165
- return super._apply(op);
181
+ return super._apply(op, isLocal);
182
+ }
183
+ /**
184
+ * INTERNAL
185
+ */
186
+ _toSerializedCrdt() {
187
+ var _a;
188
+ return {
189
+ type: live_1.CrdtType.Object,
190
+ parentId: (_a = this._parent) === null || _a === void 0 ? void 0 : _a._id,
191
+ parentKey: this._parentKey,
192
+ data: this.toObject(),
193
+ };
166
194
  }
167
195
  /**
168
196
  * Transform the LiveObject into a javascript object
@@ -186,6 +214,47 @@ class LiveObject extends AbstractCrdt_1.AbstractCrdt {
186
214
  get(key) {
187
215
  return __classPrivateFieldGet(this, _LiveObject_map, "f").get(key);
188
216
  }
217
+ /**
218
+ * Deletes a key from the LiveObject
219
+ * @param key The key of the property to delete
220
+ */
221
+ delete(key) {
222
+ const keyAsString = key;
223
+ const oldValue = __classPrivateFieldGet(this, _LiveObject_map, "f").get(keyAsString);
224
+ if (oldValue === undefined) {
225
+ return;
226
+ }
227
+ if (this._doc == null || this._id == null) {
228
+ if (oldValue instanceof AbstractCrdt_1.AbstractCrdt) {
229
+ oldValue._detach();
230
+ }
231
+ __classPrivateFieldGet(this, _LiveObject_map, "f").delete(keyAsString);
232
+ return;
233
+ }
234
+ let reverse;
235
+ if (oldValue instanceof AbstractCrdt_1.AbstractCrdt) {
236
+ oldValue._detach();
237
+ reverse = oldValue._serialize(this._id, keyAsString);
238
+ }
239
+ else {
240
+ reverse = [
241
+ {
242
+ type: live_1.OpType.UpdateObject,
243
+ data: { [keyAsString]: oldValue },
244
+ id: this._id,
245
+ },
246
+ ];
247
+ }
248
+ __classPrivateFieldGet(this, _LiveObject_map, "f").delete(keyAsString);
249
+ this._doc.dispatch([
250
+ {
251
+ type: live_1.OpType.DeleteObjectKey,
252
+ key: keyAsString,
253
+ id: this._id,
254
+ opId: this._doc.generateOpId(),
255
+ },
256
+ ], reverse, [this]);
257
+ }
189
258
  /**
190
259
  * Adds or updates multiple properties at once with an object.
191
260
  * @param overrides The object used to overrides properties
@@ -231,7 +300,7 @@ class LiveObject extends AbstractCrdt_1.AbstractCrdt {
231
300
  if (newValue instanceof AbstractCrdt_1.AbstractCrdt) {
232
301
  newValue._setParentLink(this, key);
233
302
  newValue._attach(this._doc.generateId(), this._doc);
234
- ops.push(...newValue._serialize(this._id, key));
303
+ ops.push(...newValue._serialize(this._id, key, this._doc));
235
304
  }
236
305
  else {
237
306
  updatedProps[key] = newValue;
@@ -253,7 +322,7 @@ class LiveObject extends AbstractCrdt_1.AbstractCrdt {
253
322
  }
254
323
  }
255
324
  exports.LiveObject = LiveObject;
256
- _LiveObject_map = new WeakMap(), _LiveObject_propToLastUpdate = new WeakMap(), _LiveObject_instances = new WeakSet(), _LiveObject_applyUpdate = function _LiveObject_applyUpdate(op) {
325
+ _LiveObject_map = new WeakMap(), _LiveObject_propToLastUpdate = new WeakMap(), _LiveObject_instances = new WeakSet(), _LiveObject_applyUpdate = function _LiveObject_applyUpdate(op, isLocal) {
257
326
  let isModified = false;
258
327
  const reverse = [];
259
328
  const reverseUpdate = {
@@ -275,11 +344,6 @@ _LiveObject_map = new WeakMap(), _LiveObject_propToLastUpdate = new WeakMap(), _
275
344
  reverse.push({ type: live_1.OpType.DeleteObjectKey, id: this._id, key });
276
345
  }
277
346
  }
278
- let isLocal = false;
279
- if (op.opId == null) {
280
- isLocal = true;
281
- op.opId = this._doc.generateOpId();
282
- }
283
347
  for (const key in op.data) {
284
348
  if (isLocal) {
285
349
  __classPrivateFieldGet(this, _LiveObject_propToLastUpdate, "f").set(key, op.opId);
@@ -310,6 +374,10 @@ _LiveObject_map = new WeakMap(), _LiveObject_propToLastUpdate = new WeakMap(), _
310
374
  return isModified ? { modified: this, reverse } : { modified: false };
311
375
  }, _LiveObject_applyDeleteObjectKey = function _LiveObject_applyDeleteObjectKey(op) {
312
376
  const key = op.key;
377
+ // If property does not exist, exit without notifying
378
+ if (__classPrivateFieldGet(this, _LiveObject_map, "f").has(key) === false) {
379
+ return { modified: false };
380
+ }
313
381
  const oldValue = __classPrivateFieldGet(this, _LiveObject_map, "f").get(key);
314
382
  let reverse = [];
315
383
  if ((0, utils_1.isCrdt)(oldValue)) {
@@ -1,5 +1,5 @@
1
1
  import { AbstractCrdt, Doc, ApplyResult } from "./AbstractCrdt";
2
- import { SerializedCrdtWithId, Op } from "./live";
2
+ import { SerializedCrdtWithId, Op, SerializedCrdt } from "./live";
3
3
  /**
4
4
  * INTERNAL
5
5
  */
@@ -14,8 +14,12 @@ export declare class LiveRegister<TValue = any> extends AbstractCrdt {
14
14
  /**
15
15
  * INTERNAL
16
16
  */
17
- _serialize(parentId: string, parentKey: string): Op[];
18
- _attachChild(id: string, key: string, crdt: AbstractCrdt): ApplyResult;
17
+ _serialize(parentId: string, parentKey: string, doc?: Doc): Op[];
18
+ /**
19
+ * INTERNAL
20
+ */
21
+ _toSerializedCrdt(): SerializedCrdt;
22
+ _attachChild(id: string, key: string, crdt: AbstractCrdt, isLocal: boolean): ApplyResult;
19
23
  _detachChild(crdt: AbstractCrdt): void;
20
- _apply(op: Op): ApplyResult;
24
+ _apply(op: Op, isLocal: boolean): ApplyResult;
21
25
  }
@@ -41,13 +41,14 @@ class LiveRegister extends AbstractCrdt_1.AbstractCrdt {
41
41
  /**
42
42
  * INTERNAL
43
43
  */
44
- _serialize(parentId, parentKey) {
44
+ _serialize(parentId, parentKey, doc) {
45
45
  if (this._id == null || parentId == null || parentKey == null) {
46
46
  throw new Error("Cannot serialize register if parentId or parentKey is undefined");
47
47
  }
48
48
  return [
49
49
  {
50
50
  type: live_1.OpType.CreateRegister,
51
+ opId: doc === null || doc === void 0 ? void 0 : doc.generateOpId(),
51
52
  id: this._id,
52
53
  parentId,
53
54
  parentKey,
@@ -55,14 +56,26 @@ class LiveRegister extends AbstractCrdt_1.AbstractCrdt {
55
56
  },
56
57
  ];
57
58
  }
58
- _attachChild(id, key, crdt) {
59
+ /**
60
+ * INTERNAL
61
+ */
62
+ _toSerializedCrdt() {
63
+ var _a;
64
+ return {
65
+ type: live_1.CrdtType.Register,
66
+ parentId: (_a = this._parent) === null || _a === void 0 ? void 0 : _a._id,
67
+ parentKey: this._parentKey,
68
+ data: this.data,
69
+ };
70
+ }
71
+ _attachChild(id, key, crdt, isLocal) {
59
72
  throw new Error("Method not implemented.");
60
73
  }
61
74
  _detachChild(crdt) {
62
75
  throw new Error("Method not implemented.");
63
76
  }
64
- _apply(op) {
65
- return super._apply(op);
77
+ _apply(op, isLocal) {
78
+ return super._apply(op, isLocal);
66
79
  }
67
80
  }
68
81
  exports.LiveRegister = LiveRegister;