@liveblocks/client 0.15.11 → 0.16.2

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
@@ -18,6 +18,8 @@
18
18
  </a>
19
19
  </p>
20
20
 
21
+ A client that lets you interact with [Liveblocks](https://liveblocks.io) servers.
22
+
21
23
  ## Installation
22
24
 
23
25
  ```
@@ -206,7 +206,7 @@ class LiveRegister extends AbstractCrdt {
206
206
  get data() {
207
207
  return this._data;
208
208
  }
209
- static _deserialize([id, item], parentToChildren, doc) {
209
+ static _deserialize([id, item], _parentToChildren, doc) {
210
210
  if (item.type !== CrdtType.Register) {
211
211
  throw new Error(`Tried to deserialize a map but item type is "${item.type}"`);
212
212
  }
@@ -214,7 +214,7 @@ class LiveRegister extends AbstractCrdt {
214
214
  register._attach(id, doc);
215
215
  return register;
216
216
  }
217
- _serialize(parentId, parentKey, doc) {
217
+ _serialize(parentId, parentKey, doc, intent) {
218
218
  if (this._id == null || parentId == null || parentKey == null) {
219
219
  throw new Error("Cannot serialize register if parentId or parentKey is undefined");
220
220
  }
@@ -223,6 +223,7 @@ class LiveRegister extends AbstractCrdt {
223
223
  type: OpType.CreateRegister,
224
224
  opId: doc == null ? void 0 : doc.generateOpId(),
225
225
  id: this._id,
226
+ intent,
226
227
  parentId,
227
228
  parentKey,
228
229
  data: this.data
@@ -238,7 +239,7 @@ class LiveRegister extends AbstractCrdt {
238
239
  data: this.data
239
240
  };
240
241
  }
241
- _attachChild(_id, _key, _crdt, _opId, _isLocal) {
242
+ _attachChild(_op, _isLocal) {
242
243
  throw new Error("Method not implemented.");
243
244
  }
244
245
  _detachChild(_crdt) {
@@ -276,7 +277,7 @@ class LiveList extends AbstractCrdt {
276
277
  }
277
278
  return list;
278
279
  }
279
- _serialize(parentId, parentKey, doc) {
280
+ _serialize(parentId, parentKey, doc, intent) {
280
281
  if (this._id == null) {
281
282
  throw new Error("Cannot serialize item is not attached");
282
283
  }
@@ -287,6 +288,7 @@ class LiveList extends AbstractCrdt {
287
288
  const op = {
288
289
  id: this._id,
289
290
  opId: doc == null ? void 0 : doc.generateOpId(),
291
+ intent,
290
292
  type: OpType.CreateList,
291
293
  parentId,
292
294
  parentKey
@@ -312,11 +314,14 @@ class LiveList extends AbstractCrdt {
312
314
  value._detach();
313
315
  }
314
316
  }
315
- _attachChild(id, key, child, _opId, isLocal) {
317
+ _attachChild(op, isLocal) {
316
318
  var _a;
317
319
  if (this._doc == null) {
318
320
  throw new Error("Can't attach child if doc is not present");
319
321
  }
322
+ const { id, parentKey, intent } = op;
323
+ const key = parentKey;
324
+ const child = creationOpToLiveStructure(op);
320
325
  if (this._doc.getItem(id) !== void 0) {
321
326
  return { modified: false };
322
327
  }
@@ -325,9 +330,28 @@ class LiveList extends AbstractCrdt {
325
330
  const index = this._items.findIndex((entry) => entry[1] === key);
326
331
  let newKey = key;
327
332
  if (index !== -1) {
328
- if (isLocal) {
329
- let before = this._items[index] ? this._items[index][1] : void 0;
330
- let after = this._items[index + 1] ? this._items[index + 1][1] : void 0;
333
+ if (intent === "set") {
334
+ const existingItem = this._items[index][0];
335
+ existingItem._detach();
336
+ const storageUpdate = {
337
+ node: this,
338
+ type: "LiveList",
339
+ updates: [
340
+ {
341
+ index,
342
+ type: "set",
343
+ item: child instanceof LiveRegister ? child.data : child
344
+ }
345
+ ]
346
+ };
347
+ this._items[index][0] = child;
348
+ return {
349
+ modified: storageUpdate,
350
+ reverse: existingItem._serialize(this._id, key, this._doc, "set")
351
+ };
352
+ } else if (isLocal) {
353
+ const before = this._items[index] ? this._items[index][1] : void 0;
354
+ const after = this._items[index + 1] ? this._items[index + 1][1] : void 0;
331
355
  newKey = makePosition(before, after);
332
356
  child._setParentLink(this, newKey);
333
357
  } else {
@@ -567,6 +591,33 @@ class LiveList extends AbstractCrdt {
567
591
  this._items = [];
568
592
  }
569
593
  }
594
+ set(index, item) {
595
+ if (index < 0 || index >= this._items.length) {
596
+ throw new Error(`Cannot set list item at index "${index}". index should be between 0 and ${this._items.length - 1}`);
597
+ }
598
+ const [existingItem, position] = this._items[index];
599
+ existingItem._detach();
600
+ const value = selfOrRegister(item);
601
+ value._setParentLink(this, position);
602
+ this._items[index][0] = value;
603
+ if (this._doc && this._id) {
604
+ const id = this._doc.generateId();
605
+ value._attach(id, this._doc);
606
+ const storageUpdates = /* @__PURE__ */ new Map();
607
+ storageUpdates.set(this._id, {
608
+ node: this,
609
+ type: "LiveList",
610
+ updates: [
611
+ {
612
+ index,
613
+ item: value instanceof LiveRegister ? value.data : value,
614
+ type: "set"
615
+ }
616
+ ]
617
+ });
618
+ this._doc.dispatch(value._serialize(this._id, position, this._doc, "set"), existingItem._serialize(this._id, position, void 0, "set"), storageUpdates);
619
+ }
620
+ }
570
621
  toArray() {
571
622
  return this._items.map((entry) => selfOrRegisterValue(entry[0]));
572
623
  }
@@ -643,7 +694,7 @@ class LiveMap extends AbstractCrdt {
643
694
  this._map = /* @__PURE__ */ new Map();
644
695
  }
645
696
  }
646
- _serialize(parentId, parentKey, doc) {
697
+ _serialize(parentId, parentKey, doc, intent) {
647
698
  if (this._id == null) {
648
699
  throw new Error("Cannot serialize item is not attached");
649
700
  }
@@ -655,6 +706,7 @@ class LiveMap extends AbstractCrdt {
655
706
  id: this._id,
656
707
  opId: doc == null ? void 0 : doc.generateOpId(),
657
708
  type: OpType.CreateMap,
709
+ intent,
658
710
  parentId,
659
711
  parentKey
660
712
  };
@@ -693,10 +745,13 @@ class LiveMap extends AbstractCrdt {
693
745
  }
694
746
  }
695
747
  }
696
- _attachChild(id, key, child, _opId, _isLocal) {
748
+ _attachChild(op, _isLocal) {
697
749
  if (this._doc == null) {
698
750
  throw new Error("Can't attach child if doc is not present");
699
751
  }
752
+ const { id, parentKey } = op;
753
+ const key = parentKey;
754
+ const child = creationOpToLiveStructure(op);
700
755
  if (this._doc.getItem(id) !== void 0) {
701
756
  return { modified: false };
702
757
  }
@@ -860,6 +915,20 @@ class LiveMap extends AbstractCrdt {
860
915
  }
861
916
  }
862
917
 
918
+ function parseJson(rawMessage) {
919
+ try {
920
+ return JSON.parse(rawMessage);
921
+ } catch (e) {
922
+ return void 0;
923
+ }
924
+ }
925
+ function isJsonArray(data) {
926
+ return Array.isArray(data);
927
+ }
928
+ function isJsonObject(data) {
929
+ return data !== null && typeof data === "object" && !isJsonArray(data);
930
+ }
931
+
863
932
  var __defProp$2 = Object.defineProperty;
864
933
  var __defProps$2 = Object.defineProperties;
865
934
  var __getOwnPropDescs$2 = Object.getOwnPropertyDescriptors;
@@ -887,6 +956,21 @@ function remove(array, item) {
887
956
  }
888
957
  }
889
958
  }
959
+ function compact(items) {
960
+ return items.filter((item) => item != null);
961
+ }
962
+ function creationOpToLiveStructure(op) {
963
+ switch (op.type) {
964
+ case OpType.CreateRegister:
965
+ return new LiveRegister(op.data);
966
+ case OpType.CreateObject:
967
+ return new LiveObject(op.data);
968
+ case OpType.CreateMap:
969
+ return new LiveMap();
970
+ case OpType.CreateList:
971
+ return new LiveList();
972
+ }
973
+ }
890
974
  function isSameNodeOrChildOf(node, parent) {
891
975
  if (node === parent) {
892
976
  return true;
@@ -1003,32 +1087,41 @@ function getTreesDiffOperations(currentItems, newItems) {
1003
1087
  });
1004
1088
  return ops;
1005
1089
  }
1090
+ function mergeObjectStorageUpdates(first, second) {
1091
+ const updates = first.updates;
1092
+ for (const [key, value] of entries(second.updates)) {
1093
+ updates[key] = value;
1094
+ }
1095
+ return __spreadProps$2(__spreadValues$2({}, second), {
1096
+ updates
1097
+ });
1098
+ }
1099
+ function mergeMapStorageUpdates(first, second) {
1100
+ const updates = first.updates;
1101
+ for (const [key, value] of entries(second.updates)) {
1102
+ updates[key] = value;
1103
+ }
1104
+ return __spreadProps$2(__spreadValues$2({}, second), {
1105
+ updates
1106
+ });
1107
+ }
1108
+ function mergeListStorageUpdates(first, second) {
1109
+ const updates = first.updates;
1110
+ return __spreadProps$2(__spreadValues$2({}, second), {
1111
+ updates: updates.concat(second.updates)
1112
+ });
1113
+ }
1006
1114
  function mergeStorageUpdates(first, second) {
1007
1115
  if (!first) {
1008
1116
  return second;
1009
1117
  }
1010
- if (second.type === "LiveObject") {
1011
- const updates = first.updates;
1012
- for (const [key, value] of Object.entries(second.updates)) {
1013
- updates[key] = value;
1014
- }
1015
- return __spreadProps$2(__spreadValues$2({}, second), {
1016
- updates
1017
- });
1018
- } else if (second.type === "LiveMap") {
1019
- const updates = first.updates;
1020
- for (const [key, value] of Object.entries(second.updates)) {
1021
- updates[key] = value;
1022
- }
1023
- return __spreadProps$2(__spreadValues$2({}, second), {
1024
- updates
1025
- });
1026
- } else if (second.type === "LiveList") {
1027
- const updates = first.updates;
1028
- return __spreadProps$2(__spreadValues$2({}, second), {
1029
- updates: updates.concat(second.updates)
1030
- });
1031
- }
1118
+ if (first.type === "LiveObject" && second.type === "LiveObject") {
1119
+ return mergeObjectStorageUpdates(first, second);
1120
+ } else if (first.type === "LiveMap" && second.type === "LiveMap") {
1121
+ return mergeMapStorageUpdates(first, second);
1122
+ } else if (first.type === "LiveList" && second.type === "LiveList") {
1123
+ return mergeListStorageUpdates(first, second);
1124
+ } else ;
1032
1125
  return second;
1033
1126
  }
1034
1127
  function isPlain(value) {
@@ -1075,15 +1168,12 @@ function findNonSerializableValue(value, path = "") {
1075
1168
  return false;
1076
1169
  }
1077
1170
  function isTokenValid(token) {
1078
- if (token === null) {
1079
- return false;
1080
- }
1081
1171
  const tokenParts = token.split(".");
1082
1172
  if (tokenParts.length !== 3) {
1083
1173
  return false;
1084
1174
  }
1085
- const data = JSON.parse(atob(tokenParts[1]));
1086
- if (typeof data.exp !== "number") {
1175
+ const data = parseJson(atob(tokenParts[1]));
1176
+ if (data === void 0 || !isJsonObject(data) || typeof data.exp !== "number") {
1087
1177
  return false;
1088
1178
  }
1089
1179
  const now = Date.now();
@@ -1092,6 +1182,9 @@ function isTokenValid(token) {
1092
1182
  }
1093
1183
  return true;
1094
1184
  }
1185
+ function entries(obj) {
1186
+ return Object.entries(obj);
1187
+ }
1095
1188
 
1096
1189
  class LiveObject extends AbstractCrdt {
1097
1190
  constructor(object = {}) {
@@ -1105,7 +1198,7 @@ class LiveObject extends AbstractCrdt {
1105
1198
  }
1106
1199
  this._map = new Map(Object.entries(object));
1107
1200
  }
1108
- _serialize(parentId, parentKey, doc) {
1201
+ _serialize(parentId, parentKey, doc, intent) {
1109
1202
  if (this._id == null) {
1110
1203
  throw new Error("Cannot serialize item is not attached");
1111
1204
  }
@@ -1113,6 +1206,7 @@ class LiveObject extends AbstractCrdt {
1113
1206
  const op = {
1114
1207
  id: this._id,
1115
1208
  opId: doc == null ? void 0 : doc.generateOpId(),
1209
+ intent,
1116
1210
  type: OpType.CreateObject,
1117
1211
  parentId,
1118
1212
  parentKey,
@@ -1160,10 +1254,13 @@ class LiveObject extends AbstractCrdt {
1160
1254
  }
1161
1255
  }
1162
1256
  }
1163
- _attachChild(id, key, child, opId, isLocal) {
1257
+ _attachChild(op, isLocal) {
1164
1258
  if (this._doc == null) {
1165
1259
  throw new Error("Can't attach child if doc is not present");
1166
1260
  }
1261
+ const { id, parentKey, opId } = op;
1262
+ const key = parentKey;
1263
+ const child = creationOpToLiveStructure(op);
1167
1264
  if (this._doc.getItem(id) !== void 0) {
1168
1265
  if (this._propToLastUpdate.get(key) === opId) {
1169
1266
  this._propToLastUpdate.delete(key);
@@ -1538,19 +1635,20 @@ function makeOthers(userMap) {
1538
1635
  function makeStateMachine(state, context, mockedEffects) {
1539
1636
  const effects = mockedEffects || {
1540
1637
  authenticate(auth, createWebSocket) {
1541
- if (isTokenValid(state.token)) {
1542
- const parsedToken = parseToken(state.token);
1543
- const socket = createWebSocket(state.token);
1638
+ const token = state.token;
1639
+ if (token && isTokenValid(token)) {
1640
+ const parsedToken = parseToken(token);
1641
+ const socket = createWebSocket(token);
1544
1642
  authenticationSuccess(parsedToken, socket);
1545
1643
  } else {
1546
- return auth(context.room).then(({ token }) => {
1644
+ return auth(context.roomId).then(({ token: token2 }) => {
1547
1645
  if (state.connection.state !== "authenticating") {
1548
1646
  return;
1549
1647
  }
1550
- const parsedToken = parseToken(token);
1551
- const socket = createWebSocket(token);
1648
+ const parsedToken = parseToken(token2);
1649
+ const socket = createWebSocket(token2);
1552
1650
  authenticationSuccess(parsedToken, socket);
1553
- state.token = token;
1651
+ state.token = token2;
1554
1652
  }).catch((er) => authenticationFailure(er));
1555
1653
  }
1556
1654
  },
@@ -1650,7 +1748,7 @@ function makeStateMachine(state, context, mockedEffects) {
1650
1748
  generateId,
1651
1749
  generateOpId,
1652
1750
  dispatch: storageDispatch,
1653
- roomId: context.room
1751
+ roomId: context.roomId
1654
1752
  });
1655
1753
  }
1656
1754
  function addItem(id, item) {
@@ -1793,33 +1891,15 @@ function makeStateMachine(state, context, mockedEffects) {
1793
1891
  }
1794
1892
  return { modified: false };
1795
1893
  }
1796
- case OpType.CreateObject: {
1797
- const parent = state.items.get(op.parentId);
1798
- if (parent == null) {
1799
- return { modified: false };
1800
- }
1801
- return parent._attachChild(op.id, op.parentKey, new LiveObject(op.data), op.opId, isLocal);
1802
- }
1803
- case OpType.CreateList: {
1804
- const parent = state.items.get(op.parentId);
1805
- if (parent == null) {
1806
- return { modified: false };
1807
- }
1808
- return parent._attachChild(op.id, op.parentKey, new LiveList(), op.opId, isLocal);
1809
- }
1894
+ case OpType.CreateObject:
1895
+ case OpType.CreateList:
1896
+ case OpType.CreateMap:
1810
1897
  case OpType.CreateRegister: {
1811
1898
  const parent = state.items.get(op.parentId);
1812
1899
  if (parent == null) {
1813
1900
  return { modified: false };
1814
1901
  }
1815
- return parent._attachChild(op.id, op.parentKey, new LiveRegister(op.data), op.opId, isLocal);
1816
- }
1817
- case OpType.CreateMap: {
1818
- const parent = state.items.get(op.parentId);
1819
- if (parent == null) {
1820
- return { modified: false };
1821
- }
1822
- return parent._attachChild(op.id, op.parentKey, new LiveMap(), op.opId, isLocal);
1902
+ return parent._attachChild(op, isLocal);
1823
1903
  }
1824
1904
  }
1825
1905
  return { modified: false };
@@ -1996,59 +2076,72 @@ See v0.13 release notes for more information.
1996
2076
  }
1997
2077
  return { type: "enter", user: state.users[message.actor] };
1998
2078
  }
2079
+ function parseServerMessage(data) {
2080
+ if (!isJsonObject(data)) {
2081
+ return null;
2082
+ }
2083
+ return data;
2084
+ }
2085
+ function parseServerMessages(text) {
2086
+ const data = parseJson(text);
2087
+ if (data === void 0) {
2088
+ return null;
2089
+ } else if (isJsonArray(data)) {
2090
+ return compact(data.map((item) => parseServerMessage(item)));
2091
+ } else {
2092
+ return compact([parseServerMessage(data)]);
2093
+ }
2094
+ }
1999
2095
  function onMessage(event) {
2000
2096
  if (event.data === "pong") {
2001
2097
  clearTimeout(state.timeoutHandles.pongTimeout);
2002
2098
  return;
2003
2099
  }
2004
- const message = JSON.parse(event.data);
2005
- let subMessages = [];
2006
- if (Array.isArray(message)) {
2007
- subMessages = message;
2008
- } else {
2009
- subMessages.push(message);
2100
+ const messages = parseServerMessages(event.data);
2101
+ if (messages === null || messages.length === 0) {
2102
+ return;
2010
2103
  }
2011
2104
  const updates = {
2012
2105
  storageUpdates: /* @__PURE__ */ new Map(),
2013
2106
  others: []
2014
2107
  };
2015
- for (const subMessage of subMessages) {
2016
- switch (subMessage.type) {
2108
+ for (const message of messages) {
2109
+ switch (message.type) {
2017
2110
  case ServerMessageType.UserJoined: {
2018
2111
  updates.others.push(onUserJoinedMessage(message));
2019
2112
  break;
2020
2113
  }
2021
2114
  case ServerMessageType.UpdatePresence: {
2022
- const othersPresenceUpdate = onUpdatePresenceMessage(subMessage);
2115
+ const othersPresenceUpdate = onUpdatePresenceMessage(message);
2023
2116
  if (othersPresenceUpdate) {
2024
2117
  updates.others.push(othersPresenceUpdate);
2025
2118
  }
2026
2119
  break;
2027
2120
  }
2028
2121
  case ServerMessageType.Event: {
2029
- onEvent(subMessage);
2122
+ onEvent(message);
2030
2123
  break;
2031
2124
  }
2032
2125
  case ServerMessageType.UserLeft: {
2033
- const event2 = onUserLeftMessage(subMessage);
2126
+ const event2 = onUserLeftMessage(message);
2034
2127
  if (event2) {
2035
2128
  updates.others.push(event2);
2036
2129
  }
2037
2130
  break;
2038
2131
  }
2039
2132
  case ServerMessageType.RoomState: {
2040
- updates.others.push(onRoomStateMessage(subMessage));
2133
+ updates.others.push(onRoomStateMessage(message));
2041
2134
  break;
2042
2135
  }
2043
2136
  case ServerMessageType.InitialStorageState: {
2044
2137
  const offlineOps = new Map(state.offlineOperations);
2045
- createOrUpdateRootFromMessage(subMessage);
2138
+ createOrUpdateRootFromMessage(message);
2046
2139
  applyAndSendOfflineOps(offlineOps);
2047
2140
  _getInitialStateResolver == null ? void 0 : _getInitialStateResolver();
2048
2141
  break;
2049
2142
  }
2050
2143
  case ServerMessageType.UpdateStorage: {
2051
- const applyResult = apply(subMessage.ops, false);
2144
+ const applyResult = apply(message.ops, false);
2052
2145
  applyResult.updates.storageUpdates.forEach((value, key) => {
2053
2146
  updates.storageUpdates.set(key, mergeStorageUpdates(updates.storageUpdates.get(key), value));
2054
2147
  });
@@ -2466,7 +2559,7 @@ function createRoom(options, context) {
2466
2559
  const state = defaultState(options.defaultPresence, options.defaultStorageRoot);
2467
2560
  const machine = makeStateMachine(state, context);
2468
2561
  const room = {
2469
- id: context.room,
2562
+ id: context.roomId,
2470
2563
  getConnectionState: machine.selectors.getConnectionState,
2471
2564
  getSelf: machine.selectors.getSelf,
2472
2565
  subscribe: machine.subscribe,
@@ -2507,11 +2600,15 @@ function parseToken(token) {
2507
2600
  if (tokenParts.length !== 3) {
2508
2601
  throw new Error(`Authentication error. Liveblocks could not parse the response of your authentication endpoint`);
2509
2602
  }
2510
- const data = JSON.parse(atob(tokenParts[1]));
2511
- if (typeof data.actor !== "number") {
2512
- throw new Error(`Authentication error. Liveblocks could not parse the response of your authentication endpoint`);
2603
+ const data = parseJson(atob(tokenParts[1]));
2604
+ if (data !== void 0 && isJsonObject(data) && typeof data.actor === "number" && (data.id === void 0 || typeof data.id === "string")) {
2605
+ return {
2606
+ actor: data.actor,
2607
+ id: data.id,
2608
+ info: data.info
2609
+ };
2513
2610
  }
2514
- return data;
2611
+ throw new Error(`Authentication error. Liveblocks could not parse the response of your authentication endpoint`);
2515
2612
  }
2516
2613
  function prepareCreateWebSocket(liveblocksServer, WebSocketPolyfill) {
2517
2614
  if (typeof window === "undefined" && WebSocketPolyfill == null) {
@@ -2589,7 +2686,7 @@ function createClient(options) {
2589
2686
  defaultPresence: options2.defaultPresence,
2590
2687
  defaultStorageRoot: options2.defaultStorageRoot
2591
2688
  }, {
2592
- room: roomId,
2689
+ roomId,
2593
2690
  throttleDelay,
2594
2691
  WebSocketPolyfill: clientOptions.WebSocketPolyfill,
2595
2692
  fetchPolyfill: clientOptions.fetchPolyfill,
@@ -2678,26 +2775,33 @@ var __spreadValues = (a, b) => {
2678
2775
  return a;
2679
2776
  };
2680
2777
  var __spreadProps = (a, b) => __defProps(a, __getOwnPropDescs(b));
2681
- function liveObjectToJson(liveObject) {
2778
+ function lsonObjectToJson(obj) {
2682
2779
  const result = {};
2683
- const obj = liveObject.toObject();
2684
2780
  for (const key in obj) {
2685
- result[key] = liveNodeToJson(obj[key]);
2781
+ const val = obj[key];
2782
+ if (val !== void 0) {
2783
+ result[key] = lsonToJson(val);
2784
+ }
2686
2785
  }
2687
2786
  return result;
2688
2787
  }
2788
+ function liveObjectToJson(liveObject) {
2789
+ return lsonObjectToJson(liveObject.toObject());
2790
+ }
2689
2791
  function liveMapToJson(map) {
2690
2792
  const result = {};
2691
- const obj = Object.fromEntries(map);
2692
- for (const key in obj) {
2693
- result[key] = liveNodeToJson(obj[key]);
2793
+ for (const [key, value] of map.entries()) {
2794
+ result[key] = lsonToJson(value);
2694
2795
  }
2695
2796
  return result;
2696
2797
  }
2798
+ function lsonListToJson(value) {
2799
+ return value.map(lsonToJson);
2800
+ }
2697
2801
  function liveListToJson(value) {
2698
- return value.toArray().map(liveNodeToJson);
2802
+ return lsonListToJson(value.toArray());
2699
2803
  }
2700
- function liveNodeToJson(value) {
2804
+ function lsonToJson(value) {
2701
2805
  if (value instanceof LiveObject) {
2702
2806
  return liveObjectToJson(value);
2703
2807
  } else if (value instanceof LiveList) {
@@ -2706,11 +2810,18 @@ function liveNodeToJson(value) {
2706
2810
  return liveMapToJson(value);
2707
2811
  } else if (value instanceof LiveRegister) {
2708
2812
  return value.data;
2813
+ } else if (value instanceof AbstractCrdt) {
2814
+ throw new Error("Unhandled subclass of AbstractCrdt encountered");
2815
+ }
2816
+ if (Array.isArray(value)) {
2817
+ return lsonListToJson(value);
2818
+ } else if (isPlainObject(value)) {
2819
+ return lsonObjectToJson(value);
2709
2820
  }
2710
2821
  return value;
2711
2822
  }
2712
2823
  function isPlainObject(obj) {
2713
- return Object.prototype.toString.call(obj) === "[object Object]";
2824
+ return obj !== null && Object.prototype.toString.call(obj) === "[object Object]";
2714
2825
  }
2715
2826
  function anyToCrdt(obj) {
2716
2827
  if (obj == null) {
@@ -2776,8 +2887,7 @@ function patchLiveList(liveList, prev, next) {
2776
2887
  if (liveListNode instanceof LiveObject && isPlainObject(prevNode) && isPlainObject(nextNode)) {
2777
2888
  patchLiveObject(liveListNode, prevNode, nextNode);
2778
2889
  } else {
2779
- liveList.delete(i);
2780
- liveList.insert(anyToCrdt(nextNode), i);
2890
+ liveList.set(i, anyToCrdt(nextNode));
2781
2891
  }
2782
2892
  i++;
2783
2893
  }
@@ -2785,9 +2895,10 @@ function patchLiveList(liveList, prev, next) {
2785
2895
  liveList.insert(anyToCrdt(next[i]), i);
2786
2896
  i++;
2787
2897
  }
2788
- while (i <= prevEnd) {
2898
+ let localI = i;
2899
+ while (localI <= prevEnd) {
2789
2900
  liveList.delete(i);
2790
- i++;
2901
+ localI++;
2791
2902
  }
2792
2903
  }
2793
2904
  }
@@ -2860,7 +2971,10 @@ function patchImmutableNode(state, path, update) {
2860
2971
  const newState = Object.assign({}, state);
2861
2972
  for (const key in update.updates) {
2862
2973
  if (((_a = update.updates[key]) == null ? void 0 : _a.type) === "update") {
2863
- newState[key] = liveNodeToJson(update.node.get(key));
2974
+ const val = update.node.get(key);
2975
+ if (val !== void 0) {
2976
+ newState[key] = lsonToJson(val);
2977
+ }
2864
2978
  } else if (((_b = update.updates[key]) == null ? void 0 : _b.type) === "delete") {
2865
2979
  delete newState[key];
2866
2980
  }
@@ -2873,13 +2987,15 @@ function patchImmutableNode(state, path, update) {
2873
2987
  }
2874
2988
  let newState = state.map((x) => x);
2875
2989
  for (const listUpdate of update.updates) {
2876
- if (listUpdate.type === "insert") {
2990
+ if (listUpdate.type === "set") {
2991
+ newState = newState.map((item, index) => index === listUpdate.index ? listUpdate.item : item);
2992
+ } else if (listUpdate.type === "insert") {
2877
2993
  if (listUpdate.index === newState.length) {
2878
- newState.push(liveNodeToJson(listUpdate.item));
2994
+ newState.push(lsonToJson(listUpdate.item));
2879
2995
  } else {
2880
2996
  newState = [
2881
2997
  ...newState.slice(0, listUpdate.index),
2882
- liveNodeToJson(listUpdate.item),
2998
+ lsonToJson(listUpdate.item),
2883
2999
  ...newState.slice(listUpdate.index)
2884
3000
  ];
2885
3001
  }
@@ -2889,7 +3005,7 @@ function patchImmutableNode(state, path, update) {
2889
3005
  if (listUpdate.previousIndex > listUpdate.index) {
2890
3006
  newState = [
2891
3007
  ...newState.slice(0, listUpdate.index),
2892
- liveNodeToJson(listUpdate.item),
3008
+ lsonToJson(listUpdate.item),
2893
3009
  ...newState.slice(listUpdate.index, listUpdate.previousIndex),
2894
3010
  ...newState.slice(listUpdate.previousIndex + 1)
2895
3011
  ];
@@ -2897,7 +3013,7 @@ function patchImmutableNode(state, path, update) {
2897
3013
  newState = [
2898
3014
  ...newState.slice(0, listUpdate.previousIndex),
2899
3015
  ...newState.slice(listUpdate.previousIndex + 1, listUpdate.index + 1),
2900
- liveNodeToJson(listUpdate.item),
3016
+ lsonToJson(listUpdate.item),
2901
3017
  ...newState.slice(listUpdate.index + 1)
2902
3018
  ];
2903
3019
  }
@@ -2912,7 +3028,7 @@ function patchImmutableNode(state, path, update) {
2912
3028
  const newState = Object.assign({}, state);
2913
3029
  for (const key in update.updates) {
2914
3030
  if (((_c = update.updates[key]) == null ? void 0 : _c.type) === "update") {
2915
- newState[key] = liveNodeToJson(update.node.get(key));
3031
+ newState[key] = lsonToJson(update.node.get(key));
2916
3032
  } else if (((_d = update.updates[key]) == null ? void 0 : _d.type) === "delete") {
2917
3033
  delete newState[key];
2918
3034
  }
@@ -2934,7 +3050,7 @@ function patchImmutableNode(state, path, update) {
2934
3050
 
2935
3051
  const internals = {
2936
3052
  liveObjectToJson,
2937
- liveNodeToJson,
3053
+ lsonToJson,
2938
3054
  patchLiveList,
2939
3055
  patchImmutableObject,
2940
3056
  patchLiveObject,