@liveblocks/client 0.16.9 → 0.16.10

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/index.js CHANGED
@@ -78,10 +78,10 @@ function makeStateMachine(state, context, mockedEffects) {
78
78
  })), notify(apply(LiveObject.getTreesDiffOperations(currentItems, new Map(items)), !1).updates);
79
79
  }(message.items) : state.root = (items = message.items, _buildRootAndParentTo = function(items) {
80
80
  for (var _step2, parentToChildren = new Map, root = null, _iterator2 = LiveObject._createForOfIteratorHelperLoose(items); !(_step2 = _iterator2()).done; ) {
81
- var tuple = _step2.value, parentId = tuple[1].parentId;
82
- if (null == parentId) root = tuple; else {
83
- var children = parentToChildren.get(parentId);
84
- null != children ? children.push(tuple) : parentToChildren.set(parentId, [ tuple ]);
81
+ var _step2$value = _step2.value, id = _step2$value[0], crdt = _step2$value[1];
82
+ if (LiveObject.isRootCrdt(crdt)) root = [ id, crdt ]; else {
83
+ var tuple = [ id, crdt ], children = parentToChildren.get(crdt.parentId);
84
+ null != children ? children.push(tuple) : parentToChildren.set(crdt.parentId, [ tuple ]);
85
85
  }
86
86
  }
87
87
  if (null == root) throw new Error("Root can't be null");
package/index.mjs CHANGED
@@ -1,6 +1,6 @@
1
- import { A as AbstractCrdt, r as remove, S as ServerMsgCode, m as mergeStorageUpdates, W as WebsocketCloseCodes, C as ClientMsgCode, i as isTokenValid, a as isSameNodeOrChildOf, L as LiveObject, g as getTreesDiffOperations, O as OpCode, b as LiveList, p as parseJson, c as isJsonArray, d as compact, e as isJsonObject, f as deprecateIf } from "./shared.mjs";
1
+ import { A as AbstractCrdt, r as remove, S as ServerMsgCode, m as mergeStorageUpdates, W as WebsocketCloseCodes, C as ClientMsgCode, i as isTokenValid, a as isSameNodeOrChildOf, L as LiveObject, g as getTreesDiffOperations, O as OpCode, b as LiveList, p as parseJson, c as isJsonArray, d as compact, e as isJsonObject, f as isRootCrdt, h as deprecateIf } from "./shared.mjs";
2
2
 
3
- export { b as LiveList, h as LiveMap, L as LiveObject } from "./shared.mjs";
3
+ export { b as LiveList, j as LiveMap, L as LiveObject } from "./shared.mjs";
4
4
 
5
5
  const BACKOFF_RETRY_DELAYS = [ 250, 500, 1e3, 2e3, 4e3, 8e3, 1e4 ], BACKOFF_RETRY_DELAYS_SLOW = [ 2e3, 3e4, 6e4, 3e5 ];
6
6
 
@@ -69,12 +69,9 @@ function makeStateMachine(state, context, mockedEffects) {
69
69
  const [root, parentToChildren] = function(items) {
70
70
  const parentToChildren = new Map;
71
71
  let root = null;
72
- for (const tuple of items) {
73
- const parentId = tuple[1].parentId;
74
- if (null == parentId) root = tuple; else {
75
- const children = parentToChildren.get(parentId);
76
- null != children ? children.push(tuple) : parentToChildren.set(parentId, [ tuple ]);
77
- }
72
+ for (const [id, crdt] of items) if (isRootCrdt(crdt)) root = [ id, crdt ]; else {
73
+ const tuple = [ id, crdt ], children = parentToChildren.get(crdt.parentId);
74
+ null != children ? children.push(tuple) : parentToChildren.set(crdt.parentId, [ tuple ]);
78
75
  }
79
76
  if (null == root) throw new Error("Root can't be null");
80
77
  return [ root, parentToChildren ];
package/internal.d.ts CHANGED
@@ -1,6 +1,18 @@
1
- import { d as JsonObject, J as Json, e as Lson, A as AbstractCrdt, f as LsonObject, L as LiveObject, S as StorageUpdate } from './shared';
2
- export { g as Resolve, h as RoomInitializers } from './shared';
1
+ import { d as JsonObject, J as Json, g as Resolve, e as Lson, A as AbstractCrdt, f as LsonObject, L as LiveObject, S as StorageUpdate } from './shared';
2
+ export { g as Resolve, h as RoomInitializers, p as parseJson } from './shared';
3
3
 
4
+ declare type IdTuple<T> = [id: string, value: T];
5
+ /**
6
+ * Lookup table for nodes (= SerializedCrdt values) by their IDs.
7
+ */
8
+ declare type NodeMap = Map<string, // Node ID
9
+ SerializedCrdt>;
10
+ /**
11
+ * Reverse lookup table for all child nodes (= list of SerializedCrdt values)
12
+ * by their parent node's IDs.
13
+ */
14
+ declare type ParentToChildNodeMap = Map<string, // Parent's node ID
15
+ IdTuple<SerializedChild>[]>;
4
16
  /**
5
17
  * Messages that can be sent from the server to the client.
6
18
  */
@@ -100,7 +112,6 @@ declare type BroadcastedEventServerMsg = {
100
112
  */
101
113
  event: Json;
102
114
  };
103
- declare type SerializedCrdtWithId = [id: string, crdt: SerializedCrdt];
104
115
  /**
105
116
  * Sent by the WebSocket server to a single client in response to the client
106
117
  * joining the Room, to provide the initial Storage state of the Room. The
@@ -108,7 +119,7 @@ declare type SerializedCrdtWithId = [id: string, crdt: SerializedCrdt];
108
119
  */
109
120
  declare type InitialDocumentStateServerMsg = {
110
121
  type: ServerMsgCode.INITIAL_STORAGE_STATE;
111
- items: SerializedCrdtWithId[];
122
+ items: IdTuple<SerializedCrdt>[];
112
123
  };
113
124
  /**
114
125
  * Sent by the WebSocket server and broadcasted to all clients to announce that
@@ -127,16 +138,25 @@ declare enum ClientMsgCode {
127
138
  FETCH_STORAGE = 200,
128
139
  UPDATE_STORAGE = 201
129
140
  }
141
+ declare type FetchStorageClientMsg = {
142
+ type: ClientMsgCode.FETCH_STORAGE;
143
+ };
130
144
  declare enum CrdtType {
131
145
  OBJECT = 0,
132
146
  LIST = 1,
133
147
  MAP = 2,
134
148
  REGISTER = 3
135
149
  }
150
+ declare type SerializedRootObject = {
151
+ type: CrdtType.OBJECT;
152
+ data: JsonObject;
153
+ parentId?: never;
154
+ parentKey?: never;
155
+ };
136
156
  declare type SerializedObject = {
137
157
  type: CrdtType.OBJECT;
138
- parentId?: string;
139
- parentKey?: string;
158
+ parentId: string;
159
+ parentKey: string;
140
160
  data: JsonObject;
141
161
  };
142
162
  declare type SerializedList = {
@@ -155,7 +175,10 @@ declare type SerializedRegister = {
155
175
  parentKey: string;
156
176
  data: Json;
157
177
  };
158
- declare type SerializedCrdt = SerializedObject | SerializedList | SerializedMap | SerializedRegister;
178
+ declare type SerializedCrdt = SerializedRootObject | SerializedChild;
179
+ declare type SerializedChild = SerializedObject | SerializedList | SerializedMap | SerializedRegister;
180
+ declare function isRootCrdt(crdt: SerializedCrdt): crdt is SerializedRootObject;
181
+ declare function isChildCrdt(crdt: SerializedCrdt): crdt is SerializedChild;
159
182
  declare enum OpCode {
160
183
  INIT = 0,
161
184
  SET_PARENT_KEY = 1,
@@ -171,7 +194,9 @@ declare enum OpCode {
171
194
  * These operations are the payload for {@link UpdateStorageServerMsg} messages
172
195
  * only.
173
196
  */
174
- declare type Op = CreateObjectOp | UpdateObjectOp | DeleteCrdtOp | CreateListOp | SetParentKeyOp | DeleteObjectKeyOp | CreateMapOp | CreateRegisterOp;
197
+ declare type Op = CreateOp | UpdateObjectOp | DeleteCrdtOp | SetParentKeyOp | DeleteObjectKeyOp;
198
+ declare type CreateOp = CreateRootObjectOp | CreateChildOp;
199
+ declare type CreateChildOp = CreateObjectOp | CreateRegisterOp | CreateMapOp | CreateListOp;
175
200
  declare type UpdateObjectOp = {
176
201
  opId?: string;
177
202
  id: string;
@@ -183,10 +208,14 @@ declare type CreateObjectOp = {
183
208
  id: string;
184
209
  intent?: "set";
185
210
  type: OpCode.CREATE_OBJECT;
186
- parentId?: string;
187
- parentKey?: string;
211
+ parentId: string;
212
+ parentKey: string;
188
213
  data: JsonObject;
189
214
  };
215
+ declare type CreateRootObjectOp = Resolve<Omit<CreateObjectOp, "parentId" | "parentKey"> & {
216
+ parentId?: never;
217
+ parentKey?: never;
218
+ }>;
190
219
  declare type CreateListOp = {
191
220
  opId?: string;
192
221
  id: string;
@@ -278,4 +307,25 @@ declare function patchImmutableObject<T>(state: T, updates: StorageUpdate[]): T;
278
307
  declare function makePosition(before?: string, after?: string): string;
279
308
  declare function comparePosition(posA: string, posB: string): number;
280
309
 
281
- export { ClientMsgCode, CrdtType, CreateListOp, CreateMapOp, CreateObjectOp, CreateRegisterOp, DeleteCrdtOp, DeleteObjectKeyOp, Op, OpCode, RoomStateServerMsg, SerializedCrdt, SerializedCrdtWithId, SerializedList, SerializedMap, SerializedObject, SerializedRegister, ServerMsg, ServerMsgCode, SetParentKeyOp, UpdateObjectOp, UserJoinServerMsg, WebsocketCloseCodes, comparePosition, deprecate, deprecateIf, errorIf, lsonToJson, makePosition, patchImmutableObject, patchLiveObjectKey, throwUsageError };
310
+ /**
311
+ * Helper function that can be used to implement exhaustive switch statements
312
+ * with TypeScript. Example usage:
313
+ *
314
+ * type Fruit = "🍎" | "🍌";
315
+ *
316
+ * switch (fruit) {
317
+ * case "🍎":
318
+ * case "🍌":
319
+ * return doSomething();
320
+ *
321
+ * default:
322
+ * return assertNever(fruit, "Unknown fruit");
323
+ * }
324
+ *
325
+ * If now the Fruit union is extended (i.e. add "🍒"), TypeScript will catch
326
+ * this *statically*, rather than at runtime, and force you to handle the
327
+ * 🍒 case.
328
+ */
329
+ declare function assertNever(_value: never, errmsg: string): never;
330
+
331
+ export { ClientMsgCode, CrdtType, CreateChildOp, CreateListOp, CreateMapOp, CreateObjectOp, CreateRegisterOp, CreateRootObjectOp, DeleteCrdtOp, DeleteObjectKeyOp, FetchStorageClientMsg, IdTuple, InitialDocumentStateServerMsg, NodeMap, Op, OpCode, ParentToChildNodeMap, RoomStateServerMsg, SerializedChild, SerializedCrdt, SerializedList, SerializedMap, SerializedObject, SerializedRegister, SerializedRootObject, ServerMsg, ServerMsgCode, SetParentKeyOp, UpdateObjectOp, UserJoinServerMsg, WebsocketCloseCodes, assertNever, comparePosition, deprecate, deprecateIf, errorIf, isChildCrdt, isRootCrdt, lsonToJson, makePosition, patchImmutableObject, patchLiveObjectKey, throwUsageError };
package/internal.js CHANGED
@@ -165,9 +165,11 @@ Object.defineProperty(exports, "ClientMsgCode", {
165
165
  get: function() {
166
166
  return LiveObject.WebsocketCloseCodes;
167
167
  }
168
- }), exports.comparePosition = LiveObject.comparePosition, exports.deprecate = LiveObject.deprecate,
169
- exports.deprecateIf = LiveObject.deprecateIf, exports.errorIf = LiveObject.errorIf,
170
- exports.makePosition = LiveObject.makePosition, exports.throwUsageError = LiveObject.throwUsageError,
168
+ }), exports.assertNever = LiveObject.assertNever, exports.comparePosition = LiveObject.comparePosition,
169
+ exports.deprecate = LiveObject.deprecate, exports.deprecateIf = LiveObject.deprecateIf,
170
+ exports.errorIf = LiveObject.errorIf, exports.isChildCrdt = LiveObject.isChildCrdt,
171
+ exports.isRootCrdt = LiveObject.isRootCrdt, exports.makePosition = LiveObject.makePosition,
172
+ exports.parseJson = LiveObject.parseJson, exports.throwUsageError = LiveObject.throwUsageError,
171
173
  exports.lsonToJson = lsonToJson, exports.patchImmutableObject = function(state, updates) {
172
174
  return updates.reduce((function(state, update) {
173
175
  return function(state, update) {
package/internal.mjs CHANGED
@@ -1,6 +1,6 @@
1
- import { L as LiveObject, b as LiveList, h as LiveMap, j as LiveRegister, A as AbstractCrdt, k as findNonSerializableValue } from "./shared.mjs";
1
+ import { L as LiveObject, b as LiveList, j as LiveMap, k as LiveRegister, A as AbstractCrdt, l as findNonSerializableValue } from "./shared.mjs";
2
2
 
3
- export { C as ClientMsgCode, o as CrdtType, O as OpCode, S as ServerMsgCode, W as WebsocketCloseCodes, q as comparePosition, l as deprecate, f as deprecateIf, n as errorIf, s as makePosition, t as throwUsageError } from "./shared.mjs";
3
+ export { C as ClientMsgCode, q as CrdtType, O as OpCode, S as ServerMsgCode, W as WebsocketCloseCodes, w as assertNever, s as comparePosition, n as deprecate, h as deprecateIf, o as errorIf, v as isChildCrdt, f as isRootCrdt, u as makePosition, p as parseJson, t as throwUsageError } from "./shared.mjs";
4
4
 
5
5
  function lsonObjectToJson(obj) {
6
6
  const result = {};
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@liveblocks/client",
3
- "version": "0.16.9",
3
+ "version": "0.16.10",
4
4
  "description": "A client that lets you interact with Liveblocks servers.",
5
5
  "main": "./index.js",
6
6
  "module": "./index.mjs",
package/shared.d.ts CHANGED
@@ -14,6 +14,11 @@ declare type JsonArray = Json[];
14
14
  declare type JsonObject = {
15
15
  [key: string]: Json | undefined;
16
16
  };
17
+ /**
18
+ * Alternative to JSON.parse() that will not throw in production. If the passed
19
+ * string cannot be parsed, this will return `undefined`.
20
+ */
21
+ declare function parseJson(rawMessage: string): Json | undefined;
17
22
 
18
23
  /**
19
24
  * The LiveMap class is similar to a JavaScript Map that is synchronized on all clients.
@@ -780,4 +785,4 @@ declare class LiveObject<O extends LsonObject = LsonObject> extends AbstractCrdt
780
785
  update(overrides: Partial<O>): void;
781
786
  }
782
787
 
783
- export { AbstractCrdt as A, BroadcastOptions as B, ClientOptions as C, History as H, Json as J, LiveObject as L, Others as O, Presence as P, Room as R, StorageUpdate as S, User as U, Client as a, LiveMap as b, LiveList as c, JsonObject as d, Lson as e, LsonObject as f, Resolve as g, RoomInitializers as h };
788
+ export { AbstractCrdt as A, BroadcastOptions as B, ClientOptions as C, History as H, Json as J, LiveObject as L, Others as O, Presence as P, Room as R, StorageUpdate as S, User as U, Client as a, LiveMap as b, LiveList as c, JsonObject as d, Lson as e, LsonObject as f, Resolve as g, RoomInitializers as h, parseJson as p };
package/shared.js CHANGED
@@ -124,6 +124,10 @@ function _createForOfIteratorHelperLoose(o, allowArrayLike) {
124
124
 
125
125
  var ServerMsgCode, ClientMsgCode, CrdtType, OpCode, WebsocketCloseCodes;
126
126
 
127
+ function isChildCrdt(crdt) {
128
+ return void 0 !== crdt.parentId && void 0 !== crdt.parentKey;
129
+ }
130
+
127
131
  exports.ServerMsgCode = void 0, (ServerMsgCode = exports.ServerMsgCode || (exports.ServerMsgCode = {}))[ServerMsgCode.UPDATE_PRESENCE = 100] = "UPDATE_PRESENCE",
128
132
  ServerMsgCode[ServerMsgCode.USER_JOINED = 101] = "USER_JOINED", ServerMsgCode[ServerMsgCode.USER_LEFT = 102] = "USER_LEFT",
129
133
  ServerMsgCode[ServerMsgCode.BROADCASTED_EVENT = 103] = "BROADCASTED_EVENT", ServerMsgCode[ServerMsgCode.ROOM_STATE = 104] = "ROOM_STATE",
@@ -216,9 +220,7 @@ var _Symbol$iterator$1, _Symbol$iterator2, LiveRegister = function(_AbstractCrdt
216
220
  _this;
217
221
  }
218
222
  _inheritsLoose(LiveRegister, _AbstractCrdt), LiveRegister._deserialize = function(_ref, _parentToChildren, doc) {
219
- var id = _ref[0], item = _ref[1];
220
- if (item.type !== exports.CrdtType.REGISTER) throw new Error('Tried to deserialize a map but item type is "' + item.type + '"');
221
- var register = new LiveRegister(item.data);
223
+ var id = _ref[0], register = new LiveRegister(_ref[1].data);
222
224
  return register._attach(id, doc), register;
223
225
  };
224
226
  var _proto = LiveRegister.prototype;
@@ -328,8 +330,8 @@ var LiveList = function(_AbstractCrdt) {
328
330
  void 0 === items && (items = []), (_this = _AbstractCrdt.call(this) || this)._items = void 0,
329
331
  _this._items = [];
330
332
  for (var position = void 0, i = 0; i < items.length; i++) {
331
- var newPosition = makePosition(position), _item = selfOrRegister(items[i]);
332
- _this._items.push([ _item, newPosition ]), position = newPosition;
333
+ var newPosition = makePosition(position), item = selfOrRegister(items[i]);
334
+ _this._items.push([ item, newPosition ]), position = newPosition;
333
335
  }
334
336
  return _this;
335
337
  }
@@ -511,8 +513,8 @@ var LiveList = function(_AbstractCrdt) {
511
513
  return entry[1] === position;
512
514
  }));
513
515
  if (this._doc && this._id) {
514
- var _id = this._doc.generateId();
515
- value._attach(_id, this._doc);
516
+ var id = this._doc.generateId();
517
+ value._attach(id, this._doc);
516
518
  var storageUpdates = new Map;
517
519
  storageUpdates.set(this._id, {
518
520
  node: this,
@@ -524,7 +526,7 @@ var LiveList = function(_AbstractCrdt) {
524
526
  } ]
525
527
  }), this._doc.dispatch(value._serialize(this._id, position, this._doc), [ {
526
528
  type: exports.OpCode.DELETE_CRDT,
527
- id: _id
529
+ id: id
528
530
  } ], storageUpdates);
529
531
  }
530
532
  }, _proto.move = function(index, targetIndex) {
@@ -589,14 +591,13 @@ var LiveList = function(_AbstractCrdt) {
589
591
  }, _proto.clear = function() {
590
592
  if (this._doc) {
591
593
  for (var _step5, ops = [], reverseOps = [], updateDelta = [], i = 0, _iterator5 = _createForOfIteratorHelperLoose(this._items); !(_step5 = _iterator5()).done; ) {
592
- var _item3 = _step5.value;
593
- _item3[0]._detach();
594
- var childId = _item3[0]._id;
594
+ var item = _step5.value;
595
+ item[0]._detach();
596
+ var childId = item[0]._id;
595
597
  childId && (ops.push({
596
598
  id: childId,
597
599
  type: exports.OpCode.DELETE_CRDT
598
- }), reverseOps.push.apply(reverseOps, _item3[0]._serialize(this._id, _item3[1])),
599
- updateDelta.push({
600
+ }), reverseOps.push.apply(reverseOps, item[0]._serialize(this._id, item[1])), updateDelta.push({
600
601
  index: i,
601
602
  type: "delete"
602
603
  })), i++;
@@ -620,8 +621,8 @@ var LiveList = function(_AbstractCrdt) {
620
621
  existingItem._detach();
621
622
  var value = selfOrRegister(item);
622
623
  if (value._setParentLink(this, position), this._items[index][0] = value, this._doc && this._id) {
623
- var _id2 = this._doc.generateId();
624
- value._attach(_id2, this._doc);
624
+ var id = this._doc.generateId();
625
+ value._attach(id, this._doc);
625
626
  var storageUpdates = new Map;
626
627
  storageUpdates.set(this._id, {
627
628
  node: this,
@@ -740,8 +741,8 @@ var LiveMap = function(_AbstractCrdt) {
740
741
  }
741
742
  return ops;
742
743
  }, LiveMap._deserialize = function(_ref, parentToChildren, doc) {
743
- var id = _ref[0], item = _ref[1];
744
- if (item.type !== exports.CrdtType.MAP) throw new Error('Tried to deserialize a map but item type is "' + item.type + '"');
744
+ var id = _ref[0];
745
+ _ref[1];
745
746
  var map = new LiveMap;
746
747
  map._attach(id, doc);
747
748
  var children = parentToChildren.get(id);
@@ -911,19 +912,20 @@ function creationOpToLiveStructure(op) {
911
912
  }
912
913
  }
913
914
 
914
- function deserialize(entry, parentToChildren, doc) {
915
- switch (entry[1].type) {
915
+ function deserialize(_ref, parentToChildren, doc) {
916
+ var id = _ref[0], crdt = _ref[1];
917
+ switch (crdt.type) {
916
918
  case exports.CrdtType.OBJECT:
917
- return LiveObject._deserialize(entry, parentToChildren, doc);
919
+ return LiveObject._deserialize([ id, crdt ], parentToChildren, doc);
918
920
 
919
921
  case exports.CrdtType.LIST:
920
- return LiveList._deserialize(entry, parentToChildren, doc);
922
+ return LiveList._deserialize([ id, crdt ], parentToChildren, doc);
921
923
 
922
924
  case exports.CrdtType.MAP:
923
- return LiveMap._deserialize(entry, parentToChildren, doc);
925
+ return LiveMap._deserialize([ id, crdt ], parentToChildren, doc);
924
926
 
925
927
  case exports.CrdtType.REGISTER:
926
- return LiveRegister._deserialize(entry, parentToChildren, doc);
928
+ return LiveRegister._deserialize([ id, crdt ], parentToChildren, doc);
927
929
 
928
930
  default:
929
931
  throw new Error("Unexpected CRDT type");
@@ -974,14 +976,20 @@ var LiveObject = function(_AbstractCrdt) {
974
976
  var _proto = LiveObject.prototype;
975
977
  return _proto._serialize = function(parentId, parentKey, doc, intent) {
976
978
  if (null == this._id) throw new Error("Cannot serialize item is not attached");
977
- var ops = [], op = {
979
+ var opId = null == doc ? void 0 : doc.generateOpId(), ops = [], op = void 0 !== parentId && void 0 !== parentKey ? {
980
+ type: exports.OpCode.CREATE_OBJECT,
978
981
  id: this._id,
979
- opId: null == doc ? void 0 : doc.generateOpId(),
982
+ opId: opId,
980
983
  intent: intent,
981
- type: exports.OpCode.CREATE_OBJECT,
982
984
  parentId: parentId,
983
985
  parentKey: parentKey,
984
986
  data: {}
987
+ } : {
988
+ type: exports.OpCode.CREATE_OBJECT,
989
+ id: this._id,
990
+ opId: opId,
991
+ intent: intent,
992
+ data: {}
985
993
  };
986
994
  ops.push(op);
987
995
  for (var _step, _iterator = _createForOfIteratorHelperLoose(this._map); !(_step = _iterator()).done; ) {
@@ -990,9 +998,7 @@ var LiveObject = function(_AbstractCrdt) {
990
998
  }
991
999
  return ops;
992
1000
  }, LiveObject._deserialize = function(_ref, parentToChildren, doc) {
993
- var id = _ref[0], item = _ref[1];
994
- if (item.type !== exports.CrdtType.OBJECT) throw new Error('Tried to deserialize a record but item type is "' + item.type + '"');
995
- var liveObj = new LiveObject(item.data);
1001
+ var id = _ref[0], liveObj = new LiveObject(_ref[1].data);
996
1002
  return liveObj._attach(id, doc), this._deserializeChildren(liveObj, parentToChildren, doc);
997
1003
  }, LiveObject._deserializeChildren = function(liveObj, parentToChildren, doc) {
998
1004
  var children = parentToChildren.get(liveObj._id);
@@ -1088,11 +1094,14 @@ var LiveObject = function(_AbstractCrdt) {
1088
1094
  var _step7$value = _step7.value, key = _step7$value[0], value = _step7$value[1];
1089
1095
  value instanceof AbstractCrdt == !1 && (data[key] = value);
1090
1096
  }
1091
- return {
1097
+ return void 0 !== (null == (_this$_parent = this._parent) ? void 0 : _this$_parent._id) && void 0 !== this._parentKey ? {
1092
1098
  type: exports.CrdtType.OBJECT,
1093
- parentId: null == (_this$_parent = this._parent) ? void 0 : _this$_parent._id,
1099
+ parentId: this._parent._id,
1094
1100
  parentKey: this._parentKey,
1095
1101
  data: data
1102
+ } : {
1103
+ type: exports.CrdtType.OBJECT,
1104
+ data: data
1096
1105
  };
1097
1106
  }, _proto._applyUpdate = function(op, isLocal) {
1098
1107
  var isModified = !1, reverse = [], reverseUpdate = {
@@ -1260,7 +1269,9 @@ exports._extends = _extends, exports._inheritsLoose = _inheritsLoose, exports._o
1260
1269
  var key, i, target = {}, sourceKeys = Object.keys(source);
1261
1270
  for (i = 0; i < sourceKeys.length; i++) key = sourceKeys[i], excluded.indexOf(key) >= 0 || (target[key] = source[key]);
1262
1271
  return target;
1263
- }, exports._wrapNativeSuper = _wrapNativeSuper, exports.compact = function(items) {
1272
+ }, exports._wrapNativeSuper = _wrapNativeSuper, exports.assertNever = function(_value, errmsg) {
1273
+ throw new Error(errmsg);
1274
+ }, exports.compact = function(items) {
1264
1275
  return items.filter((function(item) {
1265
1276
  return null != item;
1266
1277
  }));
@@ -1294,11 +1305,11 @@ exports.errorIf = function(condition, message) {
1294
1305
  });
1295
1306
  })), newItems.forEach((function(crdt, id) {
1296
1307
  var currentCrdt = currentItems.get(id);
1297
- if (currentCrdt) crdt.type === exports.CrdtType.OBJECT && JSON.stringify(crdt.data) !== JSON.stringify(currentCrdt.data) && ops.push({
1308
+ if (currentCrdt) crdt.type === exports.CrdtType.OBJECT && (currentCrdt.type === exports.CrdtType.OBJECT && JSON.stringify(crdt.data) === JSON.stringify(currentCrdt.data) || ops.push({
1298
1309
  type: exports.OpCode.UPDATE_OBJECT,
1299
1310
  id: id,
1300
1311
  data: crdt.data
1301
- }), crdt.parentKey !== currentCrdt.parentKey && ops.push({
1312
+ })), crdt.parentKey !== currentCrdt.parentKey && ops.push({
1302
1313
  type: exports.OpCode.SET_PARENT_KEY,
1303
1314
  id: id,
1304
1315
  parentKey: crdt.parentKey
@@ -1323,12 +1334,16 @@ exports.errorIf = function(condition, message) {
1323
1334
  break;
1324
1335
 
1325
1336
  case exports.CrdtType.OBJECT:
1326
- ops.push({
1337
+ ops.push(crdt.parentId ? {
1327
1338
  type: exports.OpCode.CREATE_OBJECT,
1328
1339
  id: id,
1329
1340
  parentId: crdt.parentId,
1330
1341
  parentKey: crdt.parentKey,
1331
1342
  data: crdt.data
1343
+ } : {
1344
+ type: exports.OpCode.CREATE_OBJECT,
1345
+ id: id,
1346
+ data: crdt.data
1332
1347
  });
1333
1348
  break;
1334
1349
 
@@ -1341,7 +1356,10 @@ exports.errorIf = function(condition, message) {
1341
1356
  });
1342
1357
  }
1343
1358
  })), ops;
1344
- }, exports.isJsonArray = isJsonArray, exports.isJsonObject = isJsonObject, exports.isSameNodeOrChildOf = function isSameNodeOrChildOf(node, parent) {
1359
+ }, exports.isChildCrdt = isChildCrdt, exports.isJsonArray = isJsonArray, exports.isJsonObject = isJsonObject,
1360
+ exports.isRootCrdt = function(crdt) {
1361
+ return crdt.type === exports.CrdtType.OBJECT && !isChildCrdt(crdt);
1362
+ }, exports.isSameNodeOrChildOf = function isSameNodeOrChildOf(node, parent) {
1345
1363
  return node === parent || !!node._parent && isSameNodeOrChildOf(node._parent, parent);
1346
1364
  }, exports.isTokenValid = function(token) {
1347
1365
  var tokenParts = token.split(".");
package/shared.mjs CHANGED
@@ -1,5 +1,13 @@
1
1
  var ServerMsgCode, ClientMsgCode, CrdtType, OpCode, WebsocketCloseCodes;
2
2
 
3
+ function isRootCrdt(crdt) {
4
+ return crdt.type === CrdtType.OBJECT && !isChildCrdt(crdt);
5
+ }
6
+
7
+ function isChildCrdt(crdt) {
8
+ return void 0 !== crdt.parentId && void 0 !== crdt.parentKey;
9
+ }
10
+
3
11
  !function(ServerMsgCode) {
4
12
  ServerMsgCode[ServerMsgCode.UPDATE_PRESENCE = 100] = "UPDATE_PRESENCE", ServerMsgCode[ServerMsgCode.USER_JOINED = 101] = "USER_JOINED",
5
13
  ServerMsgCode[ServerMsgCode.USER_LEFT = 102] = "USER_LEFT", ServerMsgCode[ServerMsgCode.BROADCASTED_EVENT = 103] = "BROADCASTED_EVENT",
@@ -86,7 +94,6 @@ class LiveRegister extends AbstractCrdt {
86
94
  return this._data;
87
95
  }
88
96
  static _deserialize([id, item], _parentToChildren, doc) {
89
- if (item.type !== CrdtType.REGISTER) throw new Error(`Tried to deserialize a map but item type is "${item.type}"`);
90
97
  const register = new LiveRegister(item.data);
91
98
  return register._attach(id, doc), register;
92
99
  }
@@ -587,8 +594,7 @@ class LiveMap extends AbstractCrdt {
587
594
  for (const [key, value] of this._map) ops.push(...value._serialize(this._id, key, doc));
588
595
  return ops;
589
596
  }
590
- static _deserialize([id, item], parentToChildren, doc) {
591
- if (item.type !== CrdtType.MAP) throw new Error(`Tried to deserialize a map but item type is "${item.type}"`);
597
+ static _deserialize([id, _item], parentToChildren, doc) {
592
598
  const map = new LiveMap;
593
599
  map._attach(id, doc);
594
600
  const children = parentToChildren.get(id);
@@ -758,6 +764,10 @@ class LiveMap extends AbstractCrdt {
758
764
  }
759
765
  }
760
766
 
767
+ function assertNever(_value, errmsg) {
768
+ throw new Error(errmsg);
769
+ }
770
+
761
771
  function remove(array, item) {
762
772
  for (let i = 0; i < array.length; i++) if (array[i] === item) {
763
773
  array.splice(i, 1);
@@ -789,19 +799,19 @@ function isSameNodeOrChildOf(node, parent) {
789
799
  return node === parent || !!node._parent && isSameNodeOrChildOf(node._parent, parent);
790
800
  }
791
801
 
792
- function deserialize(entry, parentToChildren, doc) {
793
- switch (entry[1].type) {
802
+ function deserialize([id, crdt], parentToChildren, doc) {
803
+ switch (crdt.type) {
794
804
  case CrdtType.OBJECT:
795
- return LiveObject._deserialize(entry, parentToChildren, doc);
805
+ return LiveObject._deserialize([ id, crdt ], parentToChildren, doc);
796
806
 
797
807
  case CrdtType.LIST:
798
- return LiveList._deserialize(entry, parentToChildren, doc);
808
+ return LiveList._deserialize([ id, crdt ], parentToChildren, doc);
799
809
 
800
810
  case CrdtType.MAP:
801
- return LiveMap._deserialize(entry, parentToChildren, doc);
811
+ return LiveMap._deserialize([ id, crdt ], parentToChildren, doc);
802
812
 
803
813
  case CrdtType.REGISTER:
804
- return LiveRegister._deserialize(entry, parentToChildren, doc);
814
+ return LiveRegister._deserialize([ id, crdt ], parentToChildren, doc);
805
815
 
806
816
  default:
807
817
  throw new Error("Unexpected CRDT type");
@@ -831,11 +841,11 @@ function getTreesDiffOperations(currentItems, newItems) {
831
841
  });
832
842
  })), newItems.forEach(((crdt, id) => {
833
843
  const currentCrdt = currentItems.get(id);
834
- if (currentCrdt) crdt.type === CrdtType.OBJECT && JSON.stringify(crdt.data) !== JSON.stringify(currentCrdt.data) && ops.push({
844
+ if (currentCrdt) crdt.type === CrdtType.OBJECT && (currentCrdt.type === CrdtType.OBJECT && JSON.stringify(crdt.data) === JSON.stringify(currentCrdt.data) || ops.push({
835
845
  type: OpCode.UPDATE_OBJECT,
836
846
  id: id,
837
847
  data: crdt.data
838
- }), crdt.parentKey !== currentCrdt.parentKey && ops.push({
848
+ })), crdt.parentKey !== currentCrdt.parentKey && ops.push({
839
849
  type: OpCode.SET_PARENT_KEY,
840
850
  id: id,
841
851
  parentKey: crdt.parentKey
@@ -860,12 +870,16 @@ function getTreesDiffOperations(currentItems, newItems) {
860
870
  break;
861
871
 
862
872
  case CrdtType.OBJECT:
863
- ops.push({
873
+ ops.push(crdt.parentId ? {
864
874
  type: OpCode.CREATE_OBJECT,
865
875
  id: id,
866
876
  parentId: crdt.parentId,
867
877
  parentKey: crdt.parentKey,
868
878
  data: crdt.data
879
+ } : {
880
+ type: OpCode.CREATE_OBJECT,
881
+ id: id,
882
+ data: crdt.data
869
883
  });
870
884
  break;
871
885
 
@@ -956,21 +970,26 @@ class LiveObject extends AbstractCrdt {
956
970
  }
957
971
  _serialize(parentId, parentKey, doc, intent) {
958
972
  if (null == this._id) throw new Error("Cannot serialize item is not attached");
959
- const ops = [], op = {
973
+ const opId = null == doc ? void 0 : doc.generateOpId(), ops = [], op = void 0 !== parentId && void 0 !== parentKey ? {
974
+ type: OpCode.CREATE_OBJECT,
960
975
  id: this._id,
961
- opId: null == doc ? void 0 : doc.generateOpId(),
976
+ opId: opId,
962
977
  intent: intent,
963
- type: OpCode.CREATE_OBJECT,
964
978
  parentId: parentId,
965
979
  parentKey: parentKey,
966
980
  data: {}
981
+ } : {
982
+ type: OpCode.CREATE_OBJECT,
983
+ id: this._id,
984
+ opId: opId,
985
+ intent: intent,
986
+ data: {}
967
987
  };
968
988
  ops.push(op);
969
989
  for (const [key, value] of this._map) value instanceof AbstractCrdt ? ops.push(...value._serialize(this._id, key, doc)) : op.data[key] = value;
970
990
  return ops;
971
991
  }
972
992
  static _deserialize([id, item], parentToChildren, doc) {
973
- if (item.type !== CrdtType.OBJECT) throw new Error(`Tried to deserialize a record but item type is "${item.type}"`);
974
993
  const liveObj = new LiveObject(item.data);
975
994
  return liveObj._attach(id, doc), this._deserializeChildren(liveObj, parentToChildren, doc);
976
995
  }
@@ -1065,11 +1084,14 @@ class LiveObject extends AbstractCrdt {
1065
1084
  var _a;
1066
1085
  const data = {};
1067
1086
  for (const [key, value] of this._map) value instanceof AbstractCrdt == !1 && (data[key] = value);
1068
- return {
1087
+ return void 0 !== (null === (_a = this._parent) || void 0 === _a ? void 0 : _a._id) && void 0 !== this._parentKey ? {
1069
1088
  type: CrdtType.OBJECT,
1070
- parentId: null === (_a = this._parent) || void 0 === _a ? void 0 : _a._id,
1089
+ parentId: this._parent._id,
1071
1090
  parentKey: this._parentKey,
1072
1091
  data: data
1092
+ } : {
1093
+ type: CrdtType.OBJECT,
1094
+ data: data
1073
1095
  };
1074
1096
  }
1075
1097
  _applyUpdate(op, isLocal) {
@@ -1240,4 +1262,4 @@ class LiveObject extends AbstractCrdt {
1240
1262
  }
1241
1263
  }
1242
1264
 
1243
- export { AbstractCrdt as A, ClientMsgCode as C, LiveObject as L, OpCode as O, ServerMsgCode as S, WebsocketCloseCodes as W, isSameNodeOrChildOf as a, LiveList as b, isJsonArray as c, compact as d, isJsonObject as e, deprecateIf as f, getTreesDiffOperations as g, LiveMap as h, isTokenValid as i, LiveRegister as j, findNonSerializableValue as k, deprecate as l, mergeStorageUpdates as m, errorIf as n, CrdtType as o, parseJson as p, comparePosition as q, remove as r, makePosition as s, throwUsageError as t };
1265
+ export { AbstractCrdt as A, ClientMsgCode as C, LiveObject as L, OpCode as O, ServerMsgCode as S, WebsocketCloseCodes as W, isSameNodeOrChildOf as a, LiveList as b, isJsonArray as c, compact as d, isJsonObject as e, isRootCrdt as f, getTreesDiffOperations as g, deprecateIf as h, isTokenValid as i, LiveMap as j, LiveRegister as k, findNonSerializableValue as l, mergeStorageUpdates as m, deprecate as n, errorIf as o, parseJson as p, CrdtType as q, remove as r, comparePosition as s, throwUsageError as t, makePosition as u, isChildCrdt as v, assertNever as w };