@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/lib/cjs/live.d.ts CHANGED
@@ -122,6 +122,7 @@ export declare type UpdateObjectOp = {
122
122
  };
123
123
  };
124
124
  export declare type CreateObjectOp = {
125
+ opId?: string;
125
126
  id: string;
126
127
  type: OpType.CreateObject;
127
128
  parentId?: string;
@@ -131,18 +132,21 @@ export declare type CreateObjectOp = {
131
132
  };
132
133
  };
133
134
  export declare type CreateListOp = {
135
+ opId?: string;
134
136
  id: string;
135
137
  type: OpType.CreateList;
136
138
  parentId: string;
137
139
  parentKey: string;
138
140
  };
139
141
  export declare type CreateMapOp = {
142
+ opId?: string;
140
143
  id: string;
141
144
  type: OpType.CreateMap;
142
145
  parentId: string;
143
146
  parentKey: string;
144
147
  };
145
148
  export declare type CreateRegisterOp = {
149
+ opId?: string;
146
150
  id: string;
147
151
  type: OpType.CreateRegister;
148
152
  parentId: string;
@@ -150,15 +154,18 @@ export declare type CreateRegisterOp = {
150
154
  data: any;
151
155
  };
152
156
  export declare type DeleteCrdtOp = {
157
+ opId?: string;
153
158
  id: string;
154
159
  type: OpType.DeleteCrdt;
155
160
  };
156
161
  export declare type SetParentKeyOp = {
162
+ opId?: string;
157
163
  id: string;
158
164
  type: OpType.SetParentKey;
159
165
  parentKey: string;
160
166
  };
161
167
  export declare type DeleteObjectKeyOp = {
168
+ opId?: string;
162
169
  id: string;
163
170
  type: OpType.DeleteObjectKey;
164
171
  key: string;
package/lib/cjs/room.d.ts CHANGED
@@ -11,6 +11,7 @@ declare type HistoryItem = Array<Op | {
11
11
  declare type IdFactory = () => string;
12
12
  export declare type State = {
13
13
  connection: Connection;
14
+ lastConnectionId: number | null;
14
15
  socket: WebSocket | null;
15
16
  lastFlushTime: number;
16
17
  buffer: {
@@ -62,6 +63,7 @@ export declare type State = {
62
63
  nodes: Set<AbstractCrdt>;
63
64
  };
64
65
  };
66
+ offlineOperations: Map<string, Op>;
65
67
  };
66
68
  export declare type Effects = {
67
69
  authenticate(): void;
@@ -89,6 +91,12 @@ export declare function makeStateMachine(state: State, context: Context, mockedE
89
91
  authenticationSuccess: (token: AuthenticationToken, socket: WebSocket) => void;
90
92
  heartbeat: () => void;
91
93
  onNavigatorOnline: () => void;
94
+ simulateSocketClose: () => void;
95
+ simulateSendCloseEvent: (event: {
96
+ code: number;
97
+ wasClean: boolean;
98
+ reason: any;
99
+ }) => void;
92
100
  onVisibilityChange: (visibilityState: VisibilityState) => void;
93
101
  getUndoStack: () => HistoryItem[];
94
102
  getItemsCount: () => number;
package/lib/cjs/room.js CHANGED
@@ -129,18 +129,23 @@ function makeStateMachine(state, context, mockedEffects) {
129
129
  };
130
130
  return genericSubscribe(cb);
131
131
  }
132
- function createRootFromMessage(message) {
133
- state.root = load(message.items);
132
+ function createOrUpdateRootFromMessage(message) {
133
+ if (message.items.length === 0) {
134
+ throw new Error("Internal error: cannot load storage without items");
135
+ }
136
+ if (state.root) {
137
+ updateRoot(message.items);
138
+ }
139
+ else {
140
+ state.root = load(message.items);
141
+ }
134
142
  for (const key in state.defaultStorageRoot) {
135
143
  if (state.root.get(key) == null) {
136
144
  state.root.set(key, state.defaultStorageRoot[key]);
137
145
  }
138
146
  }
139
147
  }
140
- function load(items) {
141
- if (items.length === 0) {
142
- throw new Error("Internal error: cannot load storage without items");
143
- }
148
+ function buildRootAndParentToChildren(items) {
144
149
  const parentToChildren = new Map();
145
150
  let root = null;
146
151
  for (const tuple of items) {
@@ -161,6 +166,23 @@ function makeStateMachine(state, context, mockedEffects) {
161
166
  if (root == null) {
162
167
  throw new Error("Root can't be null");
163
168
  }
169
+ return [root, parentToChildren];
170
+ }
171
+ function updateRoot(items) {
172
+ if (!state.root) {
173
+ return;
174
+ }
175
+ const currentItems = new Map();
176
+ state.items.forEach((liveCrdt, id) => {
177
+ currentItems.set(id, liveCrdt._toSerializedCrdt());
178
+ });
179
+ // Get operations that represent the diff between 2 states.
180
+ const ops = (0, utils_1.getTreesDiffOperations)(currentItems, new Map(items));
181
+ const result = apply(ops, false);
182
+ notify(result.updates);
183
+ }
184
+ function load(items) {
185
+ const [root, parentToChildren] = buildRootAndParentToChildren(items);
164
186
  return LiveObject_1.LiveObject._deserialize(root, parentToChildren, {
165
187
  addItem,
166
188
  deleteItem,
@@ -249,7 +271,10 @@ function makeStateMachine(state, context, mockedEffects) {
249
271
  state.connection.state === "connecting") {
250
272
  return state.connection.id;
251
273
  }
252
- throw new Error("Internal. Tried to get connection id but connection is not open");
274
+ else if (state.lastConnectionId !== null) {
275
+ return state.lastConnectionId;
276
+ }
277
+ throw new Error("Internal. Tried to get connection id but connection was never open");
253
278
  }
254
279
  function generateId() {
255
280
  return `${getConnectionId()}:${state.clock++}`;
@@ -257,7 +282,7 @@ function makeStateMachine(state, context, mockedEffects) {
257
282
  function generateOpId() {
258
283
  return `${getConnectionId()}:${state.opClock++}`;
259
284
  }
260
- function apply(item) {
285
+ function apply(item, isLocal) {
261
286
  const result = {
262
287
  reverse: [],
263
288
  updates: { nodes: new Set(), presence: false },
@@ -284,7 +309,11 @@ function makeStateMachine(state, context, mockedEffects) {
284
309
  result.updates.presence = true;
285
310
  }
286
311
  else {
287
- const applyOpResult = applyOp(op);
312
+ // Ops applied after undo/redo don't have an opId.
313
+ if (isLocal && !op.opId) {
314
+ op.opId = generateOpId();
315
+ }
316
+ const applyOpResult = applyOp(op, isLocal);
288
317
  if (applyOpResult.modified) {
289
318
  result.updates.nodes.add(applyOpResult.modified);
290
319
  result.reverse.unshift(...applyOpResult.reverse);
@@ -293,7 +322,10 @@ function makeStateMachine(state, context, mockedEffects) {
293
322
  }
294
323
  return result;
295
324
  }
296
- function applyOp(op) {
325
+ function applyOp(op, isLocal) {
326
+ if (op.opId) {
327
+ state.offlineOperations.delete(op.opId);
328
+ }
297
329
  switch (op.type) {
298
330
  case live_1.OpType.DeleteObjectKey:
299
331
  case live_1.OpType.UpdateObject:
@@ -302,7 +334,7 @@ function makeStateMachine(state, context, mockedEffects) {
302
334
  if (item == null) {
303
335
  return { modified: false };
304
336
  }
305
- return item._apply(op);
337
+ return item._apply(op, isLocal);
306
338
  }
307
339
  case live_1.OpType.SetParentKey: {
308
340
  const item = state.items.get(op.id);
@@ -330,28 +362,28 @@ function makeStateMachine(state, context, mockedEffects) {
330
362
  if (parent == null || getItem(op.id) != null) {
331
363
  return { modified: false };
332
364
  }
333
- return parent._attachChild(op.id, op.parentKey, new LiveObject_1.LiveObject(op.data));
365
+ return parent._attachChild(op.id, op.parentKey, new LiveObject_1.LiveObject(op.data), isLocal);
334
366
  }
335
367
  case live_1.OpType.CreateList: {
336
368
  const parent = state.items.get(op.parentId);
337
369
  if (parent == null || getItem(op.id) != null) {
338
370
  return { modified: false };
339
371
  }
340
- return parent._attachChild(op.id, op.parentKey, new LiveList_1.LiveList());
372
+ return parent._attachChild(op.id, op.parentKey, new LiveList_1.LiveList(), isLocal);
341
373
  }
342
374
  case live_1.OpType.CreateRegister: {
343
375
  const parent = state.items.get(op.parentId);
344
376
  if (parent == null || getItem(op.id) != null) {
345
377
  return { modified: false };
346
378
  }
347
- return parent._attachChild(op.id, op.parentKey, new LiveRegister_1.LiveRegister(op.data));
379
+ return parent._attachChild(op.id, op.parentKey, new LiveRegister_1.LiveRegister(op.data), isLocal);
348
380
  }
349
381
  case live_1.OpType.CreateMap: {
350
382
  const parent = state.items.get(op.parentId);
351
383
  if (parent == null || getItem(op.id) != null) {
352
384
  return { modified: false };
353
385
  }
354
- return parent._attachChild(op.id, op.parentKey, new LiveMap_1.LiveMap());
386
+ return parent._attachChild(op.id, op.parentKey, new LiveMap_1.LiveMap(), isLocal);
355
387
  }
356
388
  }
357
389
  return { modified: false };
@@ -571,12 +603,13 @@ See v0.13 release notes for more information.
571
603
  break;
572
604
  }
573
605
  case live_1.ServerMessageType.InitialStorageState: {
574
- createRootFromMessage(subMessage);
606
+ createOrUpdateRootFromMessage(subMessage);
607
+ applyAndSendOfflineOps();
575
608
  _getInitialStateResolver === null || _getInitialStateResolver === void 0 ? void 0 : _getInitialStateResolver();
576
609
  break;
577
610
  }
578
611
  case live_1.ServerMessageType.UpdateStorage: {
579
- const applyResult = apply(subMessage.ops);
612
+ const applyResult = apply(subMessage.ops, false);
580
613
  for (const node of applyResult.updates.nodes) {
581
614
  updates.nodes.add(node);
582
615
  }
@@ -609,6 +642,7 @@ See v0.13 release notes for more information.
609
642
  updateConnection({ state: "failed" });
610
643
  const error = new LiveblocksError(event.reason, event.code);
611
644
  for (const listener of state.listeners.error) {
645
+ console.error(`Liveblocks WebSocket connection closed. Reason: ${error.message} (code: ${error.code})`);
612
646
  listener(error);
613
647
  }
614
648
  }
@@ -639,6 +673,10 @@ See v0.13 release notes for more information.
639
673
  if (state.connection.state === "connecting") {
640
674
  updateConnection(Object.assign(Object.assign({}, state.connection), { state: "open" }));
641
675
  state.numberOfRetry = 0;
676
+ state.lastConnectionId = state.connection.id;
677
+ if (state.root) {
678
+ state.buffer.messages.push({ type: live_1.ClientMessageType.FetchStorage });
679
+ }
642
680
  tryFlushing();
643
681
  }
644
682
  else {
@@ -678,11 +716,29 @@ See v0.13 release notes for more information.
678
716
  clearInterval(state.intervalHandles.heartbeat);
679
717
  connect();
680
718
  }
681
- function tryFlushing() {
682
- if (state.socket == null) {
719
+ function applyAndSendOfflineOps() {
720
+ if (state.offlineOperations.size === 0) {
683
721
  return;
684
722
  }
685
- if (state.socket.readyState !== WebSocket.OPEN) {
723
+ const messages = [];
724
+ const ops = Array.from(state.offlineOperations.values());
725
+ const result = apply(ops, true);
726
+ messages.push({
727
+ type: live_1.ClientMessageType.UpdateStorage,
728
+ ops: ops,
729
+ });
730
+ notify(result.updates);
731
+ effects.send(messages);
732
+ }
733
+ function tryFlushing() {
734
+ const storageOps = state.buffer.storageOperations;
735
+ if (storageOps.length > 0) {
736
+ storageOps.forEach((op) => {
737
+ state.offlineOperations.set(op.opId, op);
738
+ });
739
+ }
740
+ if (state.socket == null || state.socket.readyState !== WebSocket.OPEN) {
741
+ state.buffer.storageOperations = [];
686
742
  return;
687
743
  }
688
744
  const now = Date.now();
@@ -800,7 +856,7 @@ See v0.13 release notes for more information.
800
856
  return;
801
857
  }
802
858
  state.isHistoryPaused = false;
803
- const result = apply(historyItem);
859
+ const result = apply(historyItem, true);
804
860
  notify(result.updates);
805
861
  state.redoStack.push(result.reverse);
806
862
  for (const op of historyItem) {
@@ -819,7 +875,7 @@ See v0.13 release notes for more information.
819
875
  return;
820
876
  }
821
877
  state.isHistoryPaused = false;
822
- const result = apply(historyItem);
878
+ const result = apply(historyItem, true);
823
879
  notify(result.updates);
824
880
  state.undoStack.push(result.reverse);
825
881
  for (const op of historyItem) {
@@ -839,10 +895,14 @@ See v0.13 release notes for more information.
839
895
  }
840
896
  finally {
841
897
  state.isBatching = false;
842
- addToUndoStack(state.batch.reverseOps);
898
+ if (state.batch.reverseOps.length > 0) {
899
+ addToUndoStack(state.batch.reverseOps);
900
+ }
843
901
  // Clear the redo stack because batch is always called from a local operation
844
902
  state.redoStack = [];
845
- dispatch(state.batch.ops);
903
+ if (state.batch.ops.length > 0) {
904
+ dispatch(state.batch.ops);
905
+ }
846
906
  notify(state.batch.updates);
847
907
  state.batch = {
848
908
  ops: [],
@@ -867,6 +927,16 @@ See v0.13 release notes for more information.
867
927
  }
868
928
  state.pausedHistory = [];
869
929
  }
930
+ function simulateSocketClose() {
931
+ if (state.socket) {
932
+ state.socket.close();
933
+ }
934
+ }
935
+ function simulateSendCloseEvent(event) {
936
+ if (state.socket) {
937
+ onClose(event);
938
+ }
939
+ }
870
940
  return {
871
941
  // Internal
872
942
  onOpen,
@@ -875,6 +945,9 @@ See v0.13 release notes for more information.
875
945
  authenticationSuccess,
876
946
  heartbeat,
877
947
  onNavigatorOnline,
948
+ // Internal dev tools
949
+ simulateSocketClose,
950
+ simulateSendCloseEvent,
878
951
  // onWakeUp,
879
952
  onVisibilityChange,
880
953
  getUndoStack: () => state.undoStack,
@@ -907,6 +980,7 @@ exports.makeStateMachine = makeStateMachine;
907
980
  function defaultState(me, defaultStorageRoot) {
908
981
  return {
909
982
  connection: { state: "closed" },
983
+ lastConnectionId: null,
910
984
  socket: null,
911
985
  listeners: {
912
986
  event: [],
@@ -951,6 +1025,7 @@ function defaultState(me, defaultStorageRoot) {
951
1025
  updates: { nodes: new Set(), presence: false, others: [] },
952
1026
  reverseOps: [],
953
1027
  },
1028
+ offlineOperations: new Map(),
954
1029
  };
955
1030
  }
956
1031
  exports.defaultState = defaultState;
@@ -997,6 +1072,11 @@ function createRoom(name, options) {
997
1072
  pause: machine.pauseHistory,
998
1073
  resume: machine.resumeHistory,
999
1074
  },
1075
+ // @ts-ignore
1076
+ internalDevTools: {
1077
+ closeWebsocket: machine.simulateSocketClose,
1078
+ sendCloseEvent: machine.simulateSendCloseEvent,
1079
+ },
1000
1080
  };
1001
1081
  return {
1002
1082
  connect: machine.connect,
@@ -277,25 +277,57 @@ export declare type Room = {
277
277
  }): () => void;
278
278
  };
279
279
  /**
280
- * Room's history contains function that let you undo and redo operation made on by the current client on the presence and storage.
280
+ * Room's history contains functions that let you undo and redo operation made on by the current client on the presence and storage.
281
281
  */
282
282
  history: {
283
283
  /**
284
284
  * Undoes the last operation executed by the current client.
285
285
  * It does not impact operations made by other clients.
286
+ *
287
+ * @example
288
+ * room.updatePresence({ selectedId: "xxx" }, { addToHistory: true });
289
+ * room.updatePresence({ selectedId: "yyy" }, { addToHistory: true });
290
+ * room.history.undo();
291
+ * // room.getPresence() equals { selectedId: "xxx" }
286
292
  */
287
293
  undo: () => void;
288
294
  /**
289
295
  * Redoes the last operation executed by the current client.
290
296
  * It does not impact operations made by other clients.
297
+ *
298
+ * @example
299
+ * room.updatePresence({ selectedId: "xxx" }, { addToHistory: true });
300
+ * room.updatePresence({ selectedId: "yyy" }, { addToHistory: true });
301
+ * room.history.undo();
302
+ * // room.getPresence() equals { selectedId: "xxx" }
303
+ * room.history.redo();
304
+ * // room.getPresence() equals { selectedId: "yyy" }
291
305
  */
292
306
  redo: () => void;
293
307
  /**
294
308
  * All future modifications made on the Room will be merged together to create a single history item until resume is called.
309
+ *
310
+ * @example
311
+ * room.updatePresence({ cursor: { x: 0, y: 0 } }, { addToHistory: true });
312
+ * room.history.pause();
313
+ * room.updatePresence({ cursor: { x: 1, y: 1 } }, { addToHistory: true });
314
+ * room.updatePresence({ cursor: { x: 2, y: 2 } }, { addToHistory: true });
315
+ * room.history.resume();
316
+ * room.history.undo();
317
+ * // room.getPresence() equals { cursor: { x: 0, y: 0 } }
295
318
  */
296
319
  pause: () => void;
297
320
  /**
298
321
  * Resumes history. Modifications made on the Room are not merged into a single history item anymore.
322
+ *
323
+ * @example
324
+ * room.updatePresence({ cursor: { x: 0, y: 0 } }, { addToHistory: true });
325
+ * room.history.pause();
326
+ * room.updatePresence({ cursor: { x: 1, y: 1 } }, { addToHistory: true });
327
+ * room.updatePresence({ cursor: { x: 2, y: 2 } }, { addToHistory: true });
328
+ * room.history.resume();
329
+ * room.history.undo();
330
+ * // room.getPresence() equals { cursor: { x: 0, y: 0 } }
299
331
  */
300
332
  resume: () => void;
301
333
  };
@@ -392,6 +424,13 @@ export declare type Room = {
392
424
  * });
393
425
  */
394
426
  broadcastEvent: (event: any) => void;
427
+ /**
428
+ * Get the room's storage asynchronously.
429
+ * The storage's root is a {@link LiveObject}.
430
+ *
431
+ * @example
432
+ * const { root } = await room.getStorage();
433
+ */
395
434
  getStorage: <TRoot>() => Promise<{
396
435
  root: LiveObject<TRoot>;
397
436
  }>;
@@ -400,6 +439,13 @@ export declare type Room = {
400
439
  * All the modifications are sent to other clients in a single message.
401
440
  * All the subscribers are called only after the batch is over.
402
441
  * All the modifications are merged in a single history item (undo/redo).
442
+ *
443
+ * @example
444
+ * const { root } = await room.getStorage();
445
+ * room.batch(() => {
446
+ * root.set("x", 0);
447
+ * room.updatePresence({ cursor: { x: 100, y: 100 }});
448
+ * });
403
449
  */
404
450
  batch: (fn: () => void) => void;
405
451
  };
@@ -1,8 +1,9 @@
1
1
  import { AbstractCrdt, Doc } from "./AbstractCrdt";
2
- import { SerializedCrdtWithId } from "./live";
2
+ import { SerializedCrdtWithId, Op, SerializedCrdt } from "./live";
3
3
  export declare function remove<T>(array: T[], item: T): void;
4
4
  export declare function isSameNodeOrChildOf(node: AbstractCrdt, parent: AbstractCrdt): boolean;
5
5
  export declare function deserialize(entry: SerializedCrdtWithId, parentToChildren: Map<string, SerializedCrdtWithId[]>, doc: Doc): AbstractCrdt;
6
6
  export declare function isCrdt(obj: any): obj is AbstractCrdt;
7
7
  export declare function selfOrRegisterValue(obj: AbstractCrdt): any;
8
8
  export declare function selfOrRegister(obj: any): AbstractCrdt;
9
+ export declare function getTreesDiffOperations(currentItems: Map<string, SerializedCrdt>, newItems: Map<string, SerializedCrdt>): Op[];
package/lib/cjs/utils.js CHANGED
@@ -1,6 +1,6 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.selfOrRegister = exports.selfOrRegisterValue = exports.isCrdt = exports.deserialize = exports.isSameNodeOrChildOf = exports.remove = void 0;
3
+ exports.getTreesDiffOperations = exports.selfOrRegister = exports.selfOrRegisterValue = exports.isCrdt = exports.deserialize = exports.isSameNodeOrChildOf = exports.remove = void 0;
4
4
  const live_1 = require("./live");
5
5
  const LiveList_1 = require("./LiveList");
6
6
  const LiveMap_1 = require("./LiveMap");
@@ -73,3 +73,78 @@ function selfOrRegister(obj) {
73
73
  }
74
74
  }
75
75
  exports.selfOrRegister = selfOrRegister;
76
+ function getTreesDiffOperations(currentItems, newItems) {
77
+ const ops = [];
78
+ currentItems.forEach((_, id) => {
79
+ if (!newItems.get(id)) {
80
+ // Delete crdt
81
+ ops.push({
82
+ type: live_1.OpType.DeleteCrdt,
83
+ id: id,
84
+ });
85
+ }
86
+ });
87
+ newItems.forEach((crdt, id) => {
88
+ const currentCrdt = currentItems.get(id);
89
+ if (currentCrdt) {
90
+ if (crdt.type === live_1.CrdtType.Object) {
91
+ if (JSON.stringify(crdt.data) !==
92
+ JSON.stringify(currentCrdt.data)) {
93
+ ops.push({
94
+ type: live_1.OpType.UpdateObject,
95
+ id: id,
96
+ data: crdt.data,
97
+ });
98
+ }
99
+ }
100
+ if (crdt.parentKey !== currentCrdt.parentKey) {
101
+ ops.push({
102
+ type: live_1.OpType.SetParentKey,
103
+ id: id,
104
+ parentKey: crdt.parentKey,
105
+ });
106
+ }
107
+ }
108
+ else {
109
+ // new Crdt
110
+ switch (crdt.type) {
111
+ case live_1.CrdtType.Register:
112
+ ops.push({
113
+ type: live_1.OpType.CreateRegister,
114
+ id: id,
115
+ parentId: crdt.parentId,
116
+ parentKey: crdt.parentKey,
117
+ data: crdt.data,
118
+ });
119
+ break;
120
+ case live_1.CrdtType.List:
121
+ ops.push({
122
+ type: live_1.OpType.CreateList,
123
+ id: id,
124
+ parentId: crdt.parentId,
125
+ parentKey: crdt.parentKey,
126
+ });
127
+ break;
128
+ case live_1.CrdtType.Object:
129
+ ops.push({
130
+ type: live_1.OpType.CreateObject,
131
+ id: id,
132
+ parentId: crdt.parentId,
133
+ parentKey: crdt.parentKey,
134
+ data: crdt.data,
135
+ });
136
+ break;
137
+ case live_1.CrdtType.Map:
138
+ ops.push({
139
+ type: live_1.OpType.CreateMap,
140
+ id: id,
141
+ parentId: crdt.parentId,
142
+ parentKey: crdt.parentKey,
143
+ });
144
+ break;
145
+ }
146
+ }
147
+ });
148
+ return ops;
149
+ }
150
+ exports.getTreesDiffOperations = getTreesDiffOperations;
@@ -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
  }
@@ -45,12 +45,12 @@ export class AbstractCrdt {
45
45
  /**
46
46
  * INTERNAL
47
47
  */
48
- _apply(op) {
48
+ _apply(op, isLocal) {
49
49
  switch (op.type) {
50
50
  case OpType.DeleteCrdt: {
51
51
  if (this._parent != null && this._parentKey != null) {
52
52
  const parent = this._parent;
53
- const reverse = this._serialize(this._parent._id, this._parentKey);
53
+ const reverse = this._serialize(this._parent._id, this._parentKey, __classPrivateFieldGet(this, _AbstractCrdt_doc, "f"));
54
54
  this._parent._detachChild(this);
55
55
  return { modified: parent, reverse };
56
56
  }
@@ -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
  */