@liveblocks/client 0.14.0 → 0.15.0-alpha.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/AbstractCrdt.d.ts +5 -3
- package/lib/cjs/AbstractCrdt.js +1 -4
- package/lib/cjs/LiveList.d.ts +8 -2
- package/lib/cjs/LiveList.js +84 -8
- package/lib/cjs/LiveMap.d.ts +5 -1
- package/lib/cjs/LiveMap.js +35 -3
- package/lib/cjs/LiveObject.d.ts +5 -1
- package/lib/cjs/LiveObject.js +65 -10
- package/lib/cjs/LiveRegister.d.ts +5 -1
- package/lib/cjs/LiveRegister.js +6 -0
- package/lib/cjs/immutable.d.ts +9 -0
- package/lib/cjs/immutable.js +272 -0
- package/lib/cjs/index.d.ts +1 -0
- package/lib/cjs/index.js +8 -1
- package/lib/cjs/room.d.ts +1 -1
- package/lib/cjs/room.js +34 -48
- package/lib/cjs/types.d.ts +20 -0
- package/lib/cjs/utils.d.ts +2 -0
- package/lib/cjs/utils.js +26 -1
- package/lib/esm/AbstractCrdt.d.ts +5 -3
- package/lib/esm/AbstractCrdt.js +1 -4
- package/lib/esm/LiveList.d.ts +8 -2
- package/lib/esm/LiveList.js +84 -8
- package/lib/esm/LiveMap.d.ts +5 -1
- package/lib/esm/LiveMap.js +35 -3
- package/lib/esm/LiveObject.d.ts +5 -1
- package/lib/esm/LiveObject.js +65 -10
- package/lib/esm/LiveRegister.d.ts +5 -1
- package/lib/esm/LiveRegister.js +6 -0
- package/lib/esm/immutable.d.ts +9 -0
- package/lib/esm/immutable.js +263 -0
- package/lib/esm/index.d.ts +1 -0
- package/lib/esm/index.js +1 -0
- package/lib/esm/room.d.ts +1 -1
- package/lib/esm/room.js +35 -49
- package/lib/esm/types.d.ts +20 -0
- package/lib/esm/utils.d.ts +2 -0
- package/lib/esm/utils.js +24 -0
- package/package.json +2 -2
|
@@ -0,0 +1,263 @@
|
|
|
1
|
+
import { LiveList } from "./LiveList";
|
|
2
|
+
import { LiveMap } from "./LiveMap";
|
|
3
|
+
import { LiveObject } from "./LiveObject";
|
|
4
|
+
import { LiveRegister } from "./LiveRegister";
|
|
5
|
+
export function liveObjectToJson(liveObject) {
|
|
6
|
+
const result = {};
|
|
7
|
+
const obj = liveObject.toObject();
|
|
8
|
+
for (const key in obj) {
|
|
9
|
+
result[key] = liveNodeToJson(obj[key]);
|
|
10
|
+
}
|
|
11
|
+
return result;
|
|
12
|
+
}
|
|
13
|
+
function liveMapToJson(map) {
|
|
14
|
+
const result = {};
|
|
15
|
+
const obj = Object.fromEntries(map);
|
|
16
|
+
for (const key in obj) {
|
|
17
|
+
result[key] = liveNodeToJson(obj[key]);
|
|
18
|
+
}
|
|
19
|
+
return result;
|
|
20
|
+
}
|
|
21
|
+
function liveListToJson(value) {
|
|
22
|
+
return value.toArray().map(liveNodeToJson);
|
|
23
|
+
}
|
|
24
|
+
export function liveNodeToJson(value) {
|
|
25
|
+
if (value instanceof LiveObject) {
|
|
26
|
+
return liveObjectToJson(value);
|
|
27
|
+
}
|
|
28
|
+
else if (value instanceof LiveList) {
|
|
29
|
+
return liveListToJson(value);
|
|
30
|
+
}
|
|
31
|
+
else if (value instanceof LiveMap) {
|
|
32
|
+
return liveMapToJson(value);
|
|
33
|
+
}
|
|
34
|
+
else if (value instanceof LiveRegister) {
|
|
35
|
+
return value.data;
|
|
36
|
+
}
|
|
37
|
+
return value;
|
|
38
|
+
}
|
|
39
|
+
function isPlainObject(obj) {
|
|
40
|
+
return Object.prototype.toString.call(obj) === "[object Object]";
|
|
41
|
+
}
|
|
42
|
+
function anyToCrdt(obj) {
|
|
43
|
+
if (obj == null) {
|
|
44
|
+
return obj;
|
|
45
|
+
}
|
|
46
|
+
if (Array.isArray(obj)) {
|
|
47
|
+
return new LiveList(obj.map(anyToCrdt));
|
|
48
|
+
}
|
|
49
|
+
if (isPlainObject(obj)) {
|
|
50
|
+
const init = {};
|
|
51
|
+
for (const key in obj) {
|
|
52
|
+
init[key] = anyToCrdt(obj[key]);
|
|
53
|
+
}
|
|
54
|
+
return new LiveObject(init);
|
|
55
|
+
}
|
|
56
|
+
return obj;
|
|
57
|
+
}
|
|
58
|
+
export function patchLiveList(liveList, prev, next) {
|
|
59
|
+
let i = 0;
|
|
60
|
+
let prevEnd = prev.length - 1;
|
|
61
|
+
let nextEnd = next.length - 1;
|
|
62
|
+
let prevNode = prev[0];
|
|
63
|
+
let nextNode = next[0];
|
|
64
|
+
/**
|
|
65
|
+
* For A,B,C => A,B,C,D
|
|
66
|
+
* i = 3, prevEnd = 2, nextEnd = 3
|
|
67
|
+
*
|
|
68
|
+
* For A,B,C => B,C
|
|
69
|
+
* i = 2, prevEnd = 2, nextEnd = 1
|
|
70
|
+
*
|
|
71
|
+
* For B,C => A,B,C
|
|
72
|
+
* i = 0, pre
|
|
73
|
+
*/
|
|
74
|
+
outer: {
|
|
75
|
+
while (prevNode === nextNode) {
|
|
76
|
+
++i;
|
|
77
|
+
if (i > prevEnd || i > nextEnd) {
|
|
78
|
+
break outer;
|
|
79
|
+
}
|
|
80
|
+
prevNode = prev[i];
|
|
81
|
+
nextNode = next[i];
|
|
82
|
+
}
|
|
83
|
+
prevNode = prev[prevEnd];
|
|
84
|
+
nextNode = next[nextEnd];
|
|
85
|
+
while (prevNode === nextNode) {
|
|
86
|
+
prevEnd--;
|
|
87
|
+
nextEnd--;
|
|
88
|
+
if (i > prevEnd || i > nextEnd) {
|
|
89
|
+
break outer;
|
|
90
|
+
}
|
|
91
|
+
prevNode = prev[prevEnd];
|
|
92
|
+
nextNode = next[nextEnd];
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
if (i > prevEnd) {
|
|
96
|
+
if (i <= nextEnd) {
|
|
97
|
+
while (i <= nextEnd) {
|
|
98
|
+
liveList.insert(anyToCrdt(next[i]), i);
|
|
99
|
+
i++;
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
else if (i > nextEnd) {
|
|
104
|
+
while (i <= prevEnd) {
|
|
105
|
+
liveList.delete(i++);
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
else {
|
|
109
|
+
while (i <= prevEnd && i <= nextEnd) {
|
|
110
|
+
prevNode = prev[i];
|
|
111
|
+
nextNode = next[i];
|
|
112
|
+
const liveListNode = liveList.get(i);
|
|
113
|
+
if (liveListNode instanceof LiveObject &&
|
|
114
|
+
isPlainObject(prevNode) &&
|
|
115
|
+
isPlainObject(nextNode)) {
|
|
116
|
+
patchLiveObject(liveListNode, prevNode, nextNode);
|
|
117
|
+
}
|
|
118
|
+
else {
|
|
119
|
+
liveList.delete(i);
|
|
120
|
+
liveList.insert(anyToCrdt(nextNode), i);
|
|
121
|
+
}
|
|
122
|
+
i++;
|
|
123
|
+
}
|
|
124
|
+
while (i <= nextEnd) {
|
|
125
|
+
liveList.insert(anyToCrdt(next[i]), i);
|
|
126
|
+
i++;
|
|
127
|
+
}
|
|
128
|
+
while (i <= prevEnd) {
|
|
129
|
+
liveList.delete(i);
|
|
130
|
+
i++;
|
|
131
|
+
}
|
|
132
|
+
}
|
|
133
|
+
}
|
|
134
|
+
export function patchLiveObjectKey(liveObject, key, prev, next) {
|
|
135
|
+
const value = liveObject.get(key);
|
|
136
|
+
if (next === undefined) {
|
|
137
|
+
liveObject.delete(key);
|
|
138
|
+
}
|
|
139
|
+
else if (value === undefined) {
|
|
140
|
+
liveObject.set(key, anyToCrdt(next));
|
|
141
|
+
}
|
|
142
|
+
else if (prev === next) {
|
|
143
|
+
return;
|
|
144
|
+
}
|
|
145
|
+
else if (value instanceof LiveList &&
|
|
146
|
+
Array.isArray(prev) &&
|
|
147
|
+
Array.isArray(next)) {
|
|
148
|
+
patchLiveList(value, prev, next);
|
|
149
|
+
}
|
|
150
|
+
else if (value instanceof LiveObject &&
|
|
151
|
+
isPlainObject(prev) &&
|
|
152
|
+
isPlainObject(next)) {
|
|
153
|
+
patchLiveObject(value, prev, next);
|
|
154
|
+
}
|
|
155
|
+
else {
|
|
156
|
+
liveObject.set(key, anyToCrdt(next));
|
|
157
|
+
}
|
|
158
|
+
}
|
|
159
|
+
export function patchLiveObject(root, prev, next) {
|
|
160
|
+
const updates = {};
|
|
161
|
+
for (const key in next) {
|
|
162
|
+
patchLiveObjectKey(root, key, prev[key], next[key]);
|
|
163
|
+
}
|
|
164
|
+
for (const key in prev) {
|
|
165
|
+
if (next[key] === undefined) {
|
|
166
|
+
root.delete(key);
|
|
167
|
+
}
|
|
168
|
+
}
|
|
169
|
+
if (Object.keys(updates).length > 0) {
|
|
170
|
+
root.update(updates);
|
|
171
|
+
}
|
|
172
|
+
}
|
|
173
|
+
function getParentsPath(node) {
|
|
174
|
+
const path = [];
|
|
175
|
+
while (node._parentKey != null && node._parent != null) {
|
|
176
|
+
if (node._parent instanceof LiveList) {
|
|
177
|
+
path.push(node._parent._indexOfPosition(node._parentKey));
|
|
178
|
+
}
|
|
179
|
+
else {
|
|
180
|
+
path.push(node._parentKey);
|
|
181
|
+
}
|
|
182
|
+
node = node._parent;
|
|
183
|
+
}
|
|
184
|
+
return path;
|
|
185
|
+
}
|
|
186
|
+
export function patchImmutableObject(state, updates) {
|
|
187
|
+
return updates.reduce((state, update) => patchImmutableObjectWithUpdate(state, update), state);
|
|
188
|
+
}
|
|
189
|
+
function patchImmutableObjectWithUpdate(state, update) {
|
|
190
|
+
const path = getParentsPath(update.node);
|
|
191
|
+
return patchImmutableNode(state, path, update);
|
|
192
|
+
}
|
|
193
|
+
function patchImmutableNode(state, path, update) {
|
|
194
|
+
var _a, _b, _c, _d;
|
|
195
|
+
const pathItem = path.pop();
|
|
196
|
+
if (pathItem === undefined) {
|
|
197
|
+
switch (update.type) {
|
|
198
|
+
case "LiveObject": {
|
|
199
|
+
if (typeof state !== "object") {
|
|
200
|
+
throw new Error("Internal: received update on LiveObject but state was not an object");
|
|
201
|
+
}
|
|
202
|
+
let newState = Object.assign({}, state);
|
|
203
|
+
for (const key in update.updates) {
|
|
204
|
+
if (((_a = update.updates[key]) === null || _a === void 0 ? void 0 : _a.type) === "update") {
|
|
205
|
+
newState[key] = liveNodeToJson(update.node.get(key));
|
|
206
|
+
}
|
|
207
|
+
else if (((_b = update.updates[key]) === null || _b === void 0 ? void 0 : _b.type) === "delete") {
|
|
208
|
+
delete newState[key];
|
|
209
|
+
}
|
|
210
|
+
}
|
|
211
|
+
return newState;
|
|
212
|
+
}
|
|
213
|
+
case "LiveList": {
|
|
214
|
+
if (Array.isArray(state) === false) {
|
|
215
|
+
throw new Error("Internal: received update on LiveList but state was not an array");
|
|
216
|
+
}
|
|
217
|
+
let newState = state.map((x) => x);
|
|
218
|
+
const newArray = update.node.toArray();
|
|
219
|
+
for (const listUpdate of update.updates) {
|
|
220
|
+
if (listUpdate.type === "insert") {
|
|
221
|
+
if (listUpdate.index === newState.length) {
|
|
222
|
+
newState.push(liveNodeToJson(newArray[listUpdate.index]));
|
|
223
|
+
}
|
|
224
|
+
else {
|
|
225
|
+
newState = [
|
|
226
|
+
...newState.slice(0, listUpdate.index),
|
|
227
|
+
liveNodeToJson(newArray[listUpdate.index]),
|
|
228
|
+
...newState.slice(listUpdate.index),
|
|
229
|
+
];
|
|
230
|
+
}
|
|
231
|
+
}
|
|
232
|
+
else if (listUpdate.type === "delete") {
|
|
233
|
+
newState.splice(listUpdate.index, 1);
|
|
234
|
+
}
|
|
235
|
+
}
|
|
236
|
+
return newState;
|
|
237
|
+
}
|
|
238
|
+
case "LiveMap": {
|
|
239
|
+
if (typeof state !== "object") {
|
|
240
|
+
throw new Error("Internal: received update on LiveMap but state was not an object");
|
|
241
|
+
}
|
|
242
|
+
let newState = Object.assign({}, state);
|
|
243
|
+
for (const key in update.updates) {
|
|
244
|
+
if (((_c = update.updates[key]) === null || _c === void 0 ? void 0 : _c.type) === "update") {
|
|
245
|
+
newState[key] = liveNodeToJson(update.node.get(key));
|
|
246
|
+
}
|
|
247
|
+
else if (((_d = update.updates[key]) === null || _d === void 0 ? void 0 : _d.type) === "delete") {
|
|
248
|
+
delete newState[key];
|
|
249
|
+
}
|
|
250
|
+
}
|
|
251
|
+
return newState;
|
|
252
|
+
}
|
|
253
|
+
}
|
|
254
|
+
}
|
|
255
|
+
if (Array.isArray(state)) {
|
|
256
|
+
const newArray = [...state];
|
|
257
|
+
newArray[pathItem] = patchImmutableNode(state[pathItem], path, update);
|
|
258
|
+
return newArray;
|
|
259
|
+
}
|
|
260
|
+
else {
|
|
261
|
+
return Object.assign(Object.assign({}, state), { [pathItem]: patchImmutableNode(state[pathItem], path, update) });
|
|
262
|
+
}
|
|
263
|
+
}
|
package/lib/esm/index.d.ts
CHANGED
|
@@ -3,3 +3,4 @@ export { LiveMap } from "./LiveMap";
|
|
|
3
3
|
export { LiveList } from "./LiveList";
|
|
4
4
|
export type { Others, Presence, Room, Client, User, BroadcastOptions, } from "./types";
|
|
5
5
|
export { createClient } from "./client";
|
|
6
|
+
export { liveObjectToJson, liveNodeToJson, patchLiveList, patchImmutableObject, patchLiveObject, patchLiveObjectKey, } from "./immutable";
|
package/lib/esm/index.js
CHANGED
|
@@ -2,3 +2,4 @@ export { LiveObject } from "./LiveObject";
|
|
|
2
2
|
export { LiveMap } from "./LiveMap";
|
|
3
3
|
export { LiveList } from "./LiveList";
|
|
4
4
|
export { createClient } from "./client";
|
|
5
|
+
export { liveObjectToJson, liveNodeToJson, patchLiveList, patchImmutableObject, patchLiveObject, patchLiveObjectKey, } from "./immutable";
|
package/lib/esm/room.d.ts
CHANGED
package/lib/esm/room.js
CHANGED
|
@@ -7,7 +7,7 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, ge
|
|
|
7
7
|
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
|
8
8
|
});
|
|
9
9
|
};
|
|
10
|
-
import { getTreesDiffOperations, isSameNodeOrChildOf, remove } from "./utils";
|
|
10
|
+
import { getTreesDiffOperations, isSameNodeOrChildOf, remove, mergeStorageUpdates, } from "./utils";
|
|
11
11
|
import auth, { parseToken } from "./authentication";
|
|
12
12
|
import { ClientMessageType, ServerMessageType, OpType, } from "./live";
|
|
13
13
|
import { LiveMap } from "./LiveMap";
|
|
@@ -193,22 +193,22 @@ export function makeStateMachine(state, context, mockedEffects) {
|
|
|
193
193
|
state.undoStack.push(historyItem);
|
|
194
194
|
}
|
|
195
195
|
}
|
|
196
|
-
function storageDispatch(ops, reverse,
|
|
196
|
+
function storageDispatch(ops, reverse, storageUpdates) {
|
|
197
197
|
if (state.isBatching) {
|
|
198
198
|
state.batch.ops.push(...ops);
|
|
199
|
-
|
|
200
|
-
state.batch.updates.
|
|
201
|
-
}
|
|
199
|
+
storageUpdates.forEach((value, key) => {
|
|
200
|
+
state.batch.updates.storageUpdates.set(key, mergeStorageUpdates(state.batch.updates.storageUpdates.get(key), value));
|
|
201
|
+
});
|
|
202
202
|
state.batch.reverseOps.push(...reverse);
|
|
203
203
|
}
|
|
204
204
|
else {
|
|
205
205
|
addToUndoStack(reverse);
|
|
206
206
|
state.redoStack = [];
|
|
207
207
|
dispatch(ops);
|
|
208
|
-
notify({
|
|
208
|
+
notify({ storageUpdates: storageUpdates });
|
|
209
209
|
}
|
|
210
210
|
}
|
|
211
|
-
function notify({
|
|
211
|
+
function notify({ storageUpdates = new Map(), presence = false, others = [], }) {
|
|
212
212
|
if (others.length > 0) {
|
|
213
213
|
state.others = makeOthers(state.users);
|
|
214
214
|
for (const event of others) {
|
|
@@ -222,28 +222,9 @@ export function makeStateMachine(state, context, mockedEffects) {
|
|
|
222
222
|
listener(state.me);
|
|
223
223
|
}
|
|
224
224
|
}
|
|
225
|
-
if (
|
|
225
|
+
if (storageUpdates.size > 0) {
|
|
226
226
|
for (const subscriber of state.listeners.storage) {
|
|
227
|
-
subscriber(Array.from(
|
|
228
|
-
if (m instanceof LiveObject) {
|
|
229
|
-
return {
|
|
230
|
-
type: "LiveObject",
|
|
231
|
-
node: m,
|
|
232
|
-
};
|
|
233
|
-
}
|
|
234
|
-
else if (m instanceof LiveList) {
|
|
235
|
-
return {
|
|
236
|
-
type: "LiveList",
|
|
237
|
-
node: m,
|
|
238
|
-
};
|
|
239
|
-
}
|
|
240
|
-
else {
|
|
241
|
-
return {
|
|
242
|
-
type: "LiveMap",
|
|
243
|
-
node: m,
|
|
244
|
-
};
|
|
245
|
-
}
|
|
246
|
-
}));
|
|
227
|
+
subscriber(Array.from(storageUpdates.values()));
|
|
247
228
|
}
|
|
248
229
|
}
|
|
249
230
|
}
|
|
@@ -266,7 +247,10 @@ export function makeStateMachine(state, context, mockedEffects) {
|
|
|
266
247
|
function apply(item, isLocal) {
|
|
267
248
|
const result = {
|
|
268
249
|
reverse: [],
|
|
269
|
-
updates: {
|
|
250
|
+
updates: {
|
|
251
|
+
storageUpdates: new Map(),
|
|
252
|
+
presence: false,
|
|
253
|
+
},
|
|
270
254
|
};
|
|
271
255
|
for (const op of item) {
|
|
272
256
|
if (op.type === "presence") {
|
|
@@ -296,7 +280,7 @@ export function makeStateMachine(state, context, mockedEffects) {
|
|
|
296
280
|
}
|
|
297
281
|
const applyOpResult = applyOp(op, isLocal);
|
|
298
282
|
if (applyOpResult.modified) {
|
|
299
|
-
result.updates.
|
|
283
|
+
result.updates.storageUpdates.set(applyOpResult.modified.node._id, mergeStorageUpdates(result.updates.storageUpdates.get(applyOpResult.modified.node._id), applyOpResult.modified));
|
|
300
284
|
result.reverse.unshift(...applyOpResult.reverse);
|
|
301
285
|
}
|
|
302
286
|
}
|
|
@@ -324,17 +308,12 @@ export function makeStateMachine(state, context, mockedEffects) {
|
|
|
324
308
|
}
|
|
325
309
|
if (item._parent instanceof LiveList) {
|
|
326
310
|
const previousKey = item._parentKey;
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
parentKey: previousKey,
|
|
334
|
-
},
|
|
335
|
-
],
|
|
336
|
-
modified: item._parent,
|
|
337
|
-
};
|
|
311
|
+
if (previousKey === op.parentKey) {
|
|
312
|
+
return { modified: false };
|
|
313
|
+
}
|
|
314
|
+
else {
|
|
315
|
+
return item._parent._setChildKey(op.parentKey, item, previousKey);
|
|
316
|
+
}
|
|
338
317
|
}
|
|
339
318
|
return { modified: false };
|
|
340
319
|
}
|
|
@@ -557,7 +536,7 @@ See v0.13 release notes for more information.
|
|
|
557
536
|
subMessages.push(message);
|
|
558
537
|
}
|
|
559
538
|
const updates = {
|
|
560
|
-
|
|
539
|
+
storageUpdates: new Map(),
|
|
561
540
|
others: [],
|
|
562
541
|
};
|
|
563
542
|
for (const subMessage of subMessages) {
|
|
@@ -593,9 +572,9 @@ See v0.13 release notes for more information.
|
|
|
593
572
|
}
|
|
594
573
|
case ServerMessageType.UpdateStorage: {
|
|
595
574
|
const applyResult = apply(subMessage.ops, false);
|
|
596
|
-
|
|
597
|
-
updates.
|
|
598
|
-
}
|
|
575
|
+
applyResult.updates.storageUpdates.forEach((value, key) => {
|
|
576
|
+
updates.storageUpdates.set(key, mergeStorageUpdates(updates.storageUpdates.get(key), value));
|
|
577
|
+
});
|
|
599
578
|
break;
|
|
600
579
|
}
|
|
601
580
|
}
|
|
@@ -889,8 +868,11 @@ See v0.13 release notes for more information.
|
|
|
889
868
|
if (state.batch.reverseOps.length > 0) {
|
|
890
869
|
addToUndoStack(state.batch.reverseOps);
|
|
891
870
|
}
|
|
892
|
-
|
|
893
|
-
|
|
871
|
+
if (state.batch.ops.length > 0) {
|
|
872
|
+
// Only clear the redo stack if something has changed during a batch
|
|
873
|
+
// Clear the redo stack because batch is always called from a local operation
|
|
874
|
+
state.redoStack = [];
|
|
875
|
+
}
|
|
894
876
|
if (state.batch.ops.length > 0) {
|
|
895
877
|
dispatch(state.batch.ops);
|
|
896
878
|
}
|
|
@@ -900,7 +882,7 @@ See v0.13 release notes for more information.
|
|
|
900
882
|
reverseOps: [],
|
|
901
883
|
updates: {
|
|
902
884
|
others: [],
|
|
903
|
-
|
|
885
|
+
storageUpdates: new Map(),
|
|
904
886
|
presence: false,
|
|
905
887
|
},
|
|
906
888
|
};
|
|
@@ -1012,7 +994,11 @@ export function defaultState(me, defaultStorageRoot) {
|
|
|
1012
994
|
isBatching: false,
|
|
1013
995
|
batch: {
|
|
1014
996
|
ops: [],
|
|
1015
|
-
updates: {
|
|
997
|
+
updates: {
|
|
998
|
+
storageUpdates: new Map(),
|
|
999
|
+
presence: false,
|
|
1000
|
+
others: [],
|
|
1001
|
+
},
|
|
1016
1002
|
reverseOps: [],
|
|
1017
1003
|
},
|
|
1018
1004
|
offlineOperations: new Map(),
|
package/lib/esm/types.d.ts
CHANGED
|
@@ -16,17 +16,37 @@ export declare type RoomEventCallbackMap = {
|
|
|
16
16
|
error: ErrorCallback;
|
|
17
17
|
connection: ConnectionCallback;
|
|
18
18
|
};
|
|
19
|
+
export declare type UpdateDelta = {
|
|
20
|
+
type: "update";
|
|
21
|
+
} | {
|
|
22
|
+
type: "delete";
|
|
23
|
+
};
|
|
19
24
|
export declare type LiveMapUpdates<TKey extends string = string, TValue = any> = {
|
|
20
25
|
type: "LiveMap";
|
|
21
26
|
node: LiveMap<TKey, TValue>;
|
|
27
|
+
updates: Record<TKey, UpdateDelta>;
|
|
22
28
|
};
|
|
29
|
+
export declare type LiveObjectUpdateDelta<T> = Partial<{
|
|
30
|
+
[Property in keyof T]: UpdateDelta;
|
|
31
|
+
}>;
|
|
23
32
|
export declare type LiveObjectUpdates<TData = any> = {
|
|
24
33
|
type: "LiveObject";
|
|
25
34
|
node: LiveObject<TData>;
|
|
35
|
+
updates: LiveObjectUpdateDelta<TData>;
|
|
36
|
+
};
|
|
37
|
+
export declare type ListUpdateDelta = {
|
|
38
|
+
type: "insert";
|
|
39
|
+
} | {
|
|
40
|
+
type: "delete";
|
|
41
|
+
};
|
|
42
|
+
export declare type LiveListUpdateDelta = {
|
|
43
|
+
index: number;
|
|
44
|
+
type: "insert" | "delete";
|
|
26
45
|
};
|
|
27
46
|
export declare type LiveListUpdates<TItem = any> = {
|
|
28
47
|
type: "LiveList";
|
|
29
48
|
node: LiveList<TItem>;
|
|
49
|
+
updates: LiveListUpdateDelta[];
|
|
30
50
|
};
|
|
31
51
|
export declare type BroadcastOptions = {
|
|
32
52
|
/**
|
package/lib/esm/utils.d.ts
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { AbstractCrdt, Doc } from "./AbstractCrdt";
|
|
2
2
|
import { SerializedCrdtWithId, Op, SerializedCrdt } from "./live";
|
|
3
|
+
import { StorageUpdate } from "./types";
|
|
3
4
|
export declare function remove<T>(array: T[], item: T): void;
|
|
4
5
|
export declare function isSameNodeOrChildOf(node: AbstractCrdt, parent: AbstractCrdt): boolean;
|
|
5
6
|
export declare function deserialize(entry: SerializedCrdtWithId, parentToChildren: Map<string, SerializedCrdtWithId[]>, doc: Doc): AbstractCrdt;
|
|
@@ -7,3 +8,4 @@ export declare function isCrdt(obj: any): obj is AbstractCrdt;
|
|
|
7
8
|
export declare function selfOrRegisterValue(obj: AbstractCrdt): any;
|
|
8
9
|
export declare function selfOrRegister(obj: any): AbstractCrdt;
|
|
9
10
|
export declare function getTreesDiffOperations(currentItems: Map<string, SerializedCrdt>, newItems: Map<string, SerializedCrdt>): Op[];
|
|
11
|
+
export declare function mergeStorageUpdates(first: StorageUpdate | undefined, second: StorageUpdate): StorageUpdate;
|
package/lib/esm/utils.js
CHANGED
|
@@ -138,3 +138,27 @@ export function getTreesDiffOperations(currentItems, newItems) {
|
|
|
138
138
|
});
|
|
139
139
|
return ops;
|
|
140
140
|
}
|
|
141
|
+
export function mergeStorageUpdates(first, second) {
|
|
142
|
+
if (!first) {
|
|
143
|
+
return second;
|
|
144
|
+
}
|
|
145
|
+
if (second.type === "LiveObject") {
|
|
146
|
+
const updates = first.updates;
|
|
147
|
+
for (const [key, value] of Object.entries(second.updates)) {
|
|
148
|
+
updates[key] = value;
|
|
149
|
+
}
|
|
150
|
+
return Object.assign(Object.assign({}, second), { updates: updates });
|
|
151
|
+
}
|
|
152
|
+
else if (second.type === "LiveMap") {
|
|
153
|
+
const updates = first.updates;
|
|
154
|
+
for (const [key, value] of Object.entries(second.updates)) {
|
|
155
|
+
updates[key] = value;
|
|
156
|
+
}
|
|
157
|
+
return Object.assign(Object.assign({}, second), { updates: updates });
|
|
158
|
+
}
|
|
159
|
+
else if (second.type === "LiveList") {
|
|
160
|
+
const updates = first.updates;
|
|
161
|
+
return Object.assign(Object.assign({}, second), { updates: updates.concat(second.updates) });
|
|
162
|
+
}
|
|
163
|
+
return second;
|
|
164
|
+
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@liveblocks/client",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.15.0-alpha.1",
|
|
4
4
|
"description": "",
|
|
5
5
|
"main": "./lib/cjs/index.js",
|
|
6
6
|
"module": "./lib/esm/index.js",
|
|
@@ -38,4 +38,4 @@
|
|
|
38
38
|
"url": "https://github.com/liveblocks/liveblocks.git",
|
|
39
39
|
"directory": "packages/liveblocks"
|
|
40
40
|
}
|
|
41
|
-
}
|
|
41
|
+
}
|