@liveblocks/client 0.15.11 → 0.16.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md 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
  ```
package/lib/esm/index.js CHANGED
@@ -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
  }
@@ -887,6 +942,18 @@ function remove(array, item) {
887
942
  }
888
943
  }
889
944
  }
945
+ function creationOpToLiveStructure(op) {
946
+ switch (op.type) {
947
+ case OpType.CreateRegister:
948
+ return new LiveRegister(op.data);
949
+ case OpType.CreateObject:
950
+ return new LiveObject(op.data);
951
+ case OpType.CreateMap:
952
+ return new LiveMap();
953
+ case OpType.CreateList:
954
+ return new LiveList();
955
+ }
956
+ }
890
957
  function isSameNodeOrChildOf(node, parent) {
891
958
  if (node === parent) {
892
959
  return true;
@@ -1003,32 +1070,41 @@ function getTreesDiffOperations(currentItems, newItems) {
1003
1070
  });
1004
1071
  return ops;
1005
1072
  }
1073
+ function mergeObjectStorageUpdates(first, second) {
1074
+ const updates = first.updates;
1075
+ for (const [key, value] of entries(second.updates)) {
1076
+ updates[key] = value;
1077
+ }
1078
+ return __spreadProps$2(__spreadValues$2({}, second), {
1079
+ updates
1080
+ });
1081
+ }
1082
+ function mergeMapStorageUpdates(first, second) {
1083
+ const updates = first.updates;
1084
+ for (const [key, value] of entries(second.updates)) {
1085
+ updates[key] = value;
1086
+ }
1087
+ return __spreadProps$2(__spreadValues$2({}, second), {
1088
+ updates
1089
+ });
1090
+ }
1091
+ function mergeListStorageUpdates(first, second) {
1092
+ const updates = first.updates;
1093
+ return __spreadProps$2(__spreadValues$2({}, second), {
1094
+ updates: updates.concat(second.updates)
1095
+ });
1096
+ }
1006
1097
  function mergeStorageUpdates(first, second) {
1007
1098
  if (!first) {
1008
1099
  return second;
1009
1100
  }
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
- }
1101
+ if (first.type === "LiveObject" && second.type === "LiveObject") {
1102
+ return mergeObjectStorageUpdates(first, second);
1103
+ } else if (first.type === "LiveMap" && second.type === "LiveMap") {
1104
+ return mergeMapStorageUpdates(first, second);
1105
+ } else if (first.type === "LiveList" && second.type === "LiveList") {
1106
+ return mergeListStorageUpdates(first, second);
1107
+ } else ;
1032
1108
  return second;
1033
1109
  }
1034
1110
  function isPlain(value) {
@@ -1092,6 +1168,9 @@ function isTokenValid(token) {
1092
1168
  }
1093
1169
  return true;
1094
1170
  }
1171
+ function entries(obj) {
1172
+ return Object.entries(obj);
1173
+ }
1095
1174
 
1096
1175
  class LiveObject extends AbstractCrdt {
1097
1176
  constructor(object = {}) {
@@ -1105,7 +1184,7 @@ class LiveObject extends AbstractCrdt {
1105
1184
  }
1106
1185
  this._map = new Map(Object.entries(object));
1107
1186
  }
1108
- _serialize(parentId, parentKey, doc) {
1187
+ _serialize(parentId, parentKey, doc, intent) {
1109
1188
  if (this._id == null) {
1110
1189
  throw new Error("Cannot serialize item is not attached");
1111
1190
  }
@@ -1113,6 +1192,7 @@ class LiveObject extends AbstractCrdt {
1113
1192
  const op = {
1114
1193
  id: this._id,
1115
1194
  opId: doc == null ? void 0 : doc.generateOpId(),
1195
+ intent,
1116
1196
  type: OpType.CreateObject,
1117
1197
  parentId,
1118
1198
  parentKey,
@@ -1160,10 +1240,13 @@ class LiveObject extends AbstractCrdt {
1160
1240
  }
1161
1241
  }
1162
1242
  }
1163
- _attachChild(id, key, child, opId, isLocal) {
1243
+ _attachChild(op, isLocal) {
1164
1244
  if (this._doc == null) {
1165
1245
  throw new Error("Can't attach child if doc is not present");
1166
1246
  }
1247
+ const { id, parentKey, opId } = op;
1248
+ const key = parentKey;
1249
+ const child = creationOpToLiveStructure(op);
1167
1250
  if (this._doc.getItem(id) !== void 0) {
1168
1251
  if (this._propToLastUpdate.get(key) === opId) {
1169
1252
  this._propToLastUpdate.delete(key);
@@ -1793,33 +1876,15 @@ function makeStateMachine(state, context, mockedEffects) {
1793
1876
  }
1794
1877
  return { modified: false };
1795
1878
  }
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
- }
1879
+ case OpType.CreateObject:
1880
+ case OpType.CreateList:
1881
+ case OpType.CreateMap:
1810
1882
  case OpType.CreateRegister: {
1811
1883
  const parent = state.items.get(op.parentId);
1812
1884
  if (parent == null) {
1813
1885
  return { modified: false };
1814
1886
  }
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);
1887
+ return parent._attachChild(op, isLocal);
1823
1888
  }
1824
1889
  }
1825
1890
  return { modified: false };
@@ -2678,26 +2743,30 @@ var __spreadValues = (a, b) => {
2678
2743
  return a;
2679
2744
  };
2680
2745
  var __spreadProps = (a, b) => __defProps(a, __getOwnPropDescs(b));
2681
- function liveObjectToJson(liveObject) {
2746
+ function lsonObjectToJson(obj) {
2682
2747
  const result = {};
2683
- const obj = liveObject.toObject();
2684
2748
  for (const key in obj) {
2685
- result[key] = liveNodeToJson(obj[key]);
2749
+ result[key] = lsonToJson(obj[key]);
2686
2750
  }
2687
2751
  return result;
2688
2752
  }
2753
+ function liveObjectToJson(liveObject) {
2754
+ return lsonObjectToJson(liveObject.toObject());
2755
+ }
2689
2756
  function liveMapToJson(map) {
2690
2757
  const result = {};
2691
- const obj = Object.fromEntries(map);
2692
- for (const key in obj) {
2693
- result[key] = liveNodeToJson(obj[key]);
2758
+ for (const [key, value] of map.entries()) {
2759
+ result[key] = lsonToJson(value);
2694
2760
  }
2695
2761
  return result;
2696
2762
  }
2763
+ function lsonListToJson(value) {
2764
+ return value.map(lsonToJson);
2765
+ }
2697
2766
  function liveListToJson(value) {
2698
- return value.toArray().map(liveNodeToJson);
2767
+ return lsonListToJson(value.toArray());
2699
2768
  }
2700
- function liveNodeToJson(value) {
2769
+ function lsonToJson(value) {
2701
2770
  if (value instanceof LiveObject) {
2702
2771
  return liveObjectToJson(value);
2703
2772
  } else if (value instanceof LiveList) {
@@ -2706,11 +2775,18 @@ function liveNodeToJson(value) {
2706
2775
  return liveMapToJson(value);
2707
2776
  } else if (value instanceof LiveRegister) {
2708
2777
  return value.data;
2778
+ } else if (value instanceof AbstractCrdt) {
2779
+ throw new Error("Unhandled subclass of AbstractCrdt encountered");
2780
+ }
2781
+ if (Array.isArray(value)) {
2782
+ return lsonListToJson(value);
2783
+ } else if (isPlainObject(value)) {
2784
+ return lsonObjectToJson(value);
2709
2785
  }
2710
2786
  return value;
2711
2787
  }
2712
2788
  function isPlainObject(obj) {
2713
- return Object.prototype.toString.call(obj) === "[object Object]";
2789
+ return obj !== null && Object.prototype.toString.call(obj) === "[object Object]";
2714
2790
  }
2715
2791
  function anyToCrdt(obj) {
2716
2792
  if (obj == null) {
@@ -2776,8 +2852,7 @@ function patchLiveList(liveList, prev, next) {
2776
2852
  if (liveListNode instanceof LiveObject && isPlainObject(prevNode) && isPlainObject(nextNode)) {
2777
2853
  patchLiveObject(liveListNode, prevNode, nextNode);
2778
2854
  } else {
2779
- liveList.delete(i);
2780
- liveList.insert(anyToCrdt(nextNode), i);
2855
+ liveList.set(i, anyToCrdt(nextNode));
2781
2856
  }
2782
2857
  i++;
2783
2858
  }
@@ -2785,9 +2860,10 @@ function patchLiveList(liveList, prev, next) {
2785
2860
  liveList.insert(anyToCrdt(next[i]), i);
2786
2861
  i++;
2787
2862
  }
2788
- while (i <= prevEnd) {
2863
+ let localI = i;
2864
+ while (localI <= prevEnd) {
2789
2865
  liveList.delete(i);
2790
- i++;
2866
+ localI++;
2791
2867
  }
2792
2868
  }
2793
2869
  }
@@ -2860,7 +2936,7 @@ function patchImmutableNode(state, path, update) {
2860
2936
  const newState = Object.assign({}, state);
2861
2937
  for (const key in update.updates) {
2862
2938
  if (((_a = update.updates[key]) == null ? void 0 : _a.type) === "update") {
2863
- newState[key] = liveNodeToJson(update.node.get(key));
2939
+ newState[key] = lsonToJson(update.node.get(key));
2864
2940
  } else if (((_b = update.updates[key]) == null ? void 0 : _b.type) === "delete") {
2865
2941
  delete newState[key];
2866
2942
  }
@@ -2873,13 +2949,15 @@ function patchImmutableNode(state, path, update) {
2873
2949
  }
2874
2950
  let newState = state.map((x) => x);
2875
2951
  for (const listUpdate of update.updates) {
2876
- if (listUpdate.type === "insert") {
2952
+ if (listUpdate.type === "set") {
2953
+ newState = newState.map((item, index) => index === listUpdate.index ? listUpdate.item : item);
2954
+ } else if (listUpdate.type === "insert") {
2877
2955
  if (listUpdate.index === newState.length) {
2878
- newState.push(liveNodeToJson(listUpdate.item));
2956
+ newState.push(lsonToJson(listUpdate.item));
2879
2957
  } else {
2880
2958
  newState = [
2881
2959
  ...newState.slice(0, listUpdate.index),
2882
- liveNodeToJson(listUpdate.item),
2960
+ lsonToJson(listUpdate.item),
2883
2961
  ...newState.slice(listUpdate.index)
2884
2962
  ];
2885
2963
  }
@@ -2889,7 +2967,7 @@ function patchImmutableNode(state, path, update) {
2889
2967
  if (listUpdate.previousIndex > listUpdate.index) {
2890
2968
  newState = [
2891
2969
  ...newState.slice(0, listUpdate.index),
2892
- liveNodeToJson(listUpdate.item),
2970
+ lsonToJson(listUpdate.item),
2893
2971
  ...newState.slice(listUpdate.index, listUpdate.previousIndex),
2894
2972
  ...newState.slice(listUpdate.previousIndex + 1)
2895
2973
  ];
@@ -2897,7 +2975,7 @@ function patchImmutableNode(state, path, update) {
2897
2975
  newState = [
2898
2976
  ...newState.slice(0, listUpdate.previousIndex),
2899
2977
  ...newState.slice(listUpdate.previousIndex + 1, listUpdate.index + 1),
2900
- liveNodeToJson(listUpdate.item),
2978
+ lsonToJson(listUpdate.item),
2901
2979
  ...newState.slice(listUpdate.index + 1)
2902
2980
  ];
2903
2981
  }
@@ -2912,7 +2990,7 @@ function patchImmutableNode(state, path, update) {
2912
2990
  const newState = Object.assign({}, state);
2913
2991
  for (const key in update.updates) {
2914
2992
  if (((_c = update.updates[key]) == null ? void 0 : _c.type) === "update") {
2915
- newState[key] = liveNodeToJson(update.node.get(key));
2993
+ newState[key] = lsonToJson(update.node.get(key));
2916
2994
  } else if (((_d = update.updates[key]) == null ? void 0 : _d.type) === "delete") {
2917
2995
  delete newState[key];
2918
2996
  }
@@ -2934,7 +3012,7 @@ function patchImmutableNode(state, path, update) {
2934
3012
 
2935
3013
  const internals = {
2936
3014
  liveObjectToJson,
2937
- liveNodeToJson,
3015
+ lsonToJson,
2938
3016
  patchLiveList,
2939
3017
  patchImmutableObject,
2940
3018
  patchLiveObject,