@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,272 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.patchImmutableObject = exports.patchLiveObject = exports.patchLiveObjectKey = exports.patchLiveList = exports.liveNodeToJson = exports.liveObjectToJson = void 0;
|
|
4
|
+
const LiveList_1 = require("./LiveList");
|
|
5
|
+
const LiveMap_1 = require("./LiveMap");
|
|
6
|
+
const LiveObject_1 = require("./LiveObject");
|
|
7
|
+
const LiveRegister_1 = require("./LiveRegister");
|
|
8
|
+
function liveObjectToJson(liveObject) {
|
|
9
|
+
const result = {};
|
|
10
|
+
const obj = liveObject.toObject();
|
|
11
|
+
for (const key in obj) {
|
|
12
|
+
result[key] = liveNodeToJson(obj[key]);
|
|
13
|
+
}
|
|
14
|
+
return result;
|
|
15
|
+
}
|
|
16
|
+
exports.liveObjectToJson = liveObjectToJson;
|
|
17
|
+
function liveMapToJson(map) {
|
|
18
|
+
const result = {};
|
|
19
|
+
const obj = Object.fromEntries(map);
|
|
20
|
+
for (const key in obj) {
|
|
21
|
+
result[key] = liveNodeToJson(obj[key]);
|
|
22
|
+
}
|
|
23
|
+
return result;
|
|
24
|
+
}
|
|
25
|
+
function liveListToJson(value) {
|
|
26
|
+
return value.toArray().map(liveNodeToJson);
|
|
27
|
+
}
|
|
28
|
+
function liveNodeToJson(value) {
|
|
29
|
+
if (value instanceof LiveObject_1.LiveObject) {
|
|
30
|
+
return liveObjectToJson(value);
|
|
31
|
+
}
|
|
32
|
+
else if (value instanceof LiveList_1.LiveList) {
|
|
33
|
+
return liveListToJson(value);
|
|
34
|
+
}
|
|
35
|
+
else if (value instanceof LiveMap_1.LiveMap) {
|
|
36
|
+
return liveMapToJson(value);
|
|
37
|
+
}
|
|
38
|
+
else if (value instanceof LiveRegister_1.LiveRegister) {
|
|
39
|
+
return value.data;
|
|
40
|
+
}
|
|
41
|
+
return value;
|
|
42
|
+
}
|
|
43
|
+
exports.liveNodeToJson = liveNodeToJson;
|
|
44
|
+
function isPlainObject(obj) {
|
|
45
|
+
return Object.prototype.toString.call(obj) === "[object Object]";
|
|
46
|
+
}
|
|
47
|
+
function anyToCrdt(obj) {
|
|
48
|
+
if (obj == null) {
|
|
49
|
+
return obj;
|
|
50
|
+
}
|
|
51
|
+
if (Array.isArray(obj)) {
|
|
52
|
+
return new LiveList_1.LiveList(obj.map(anyToCrdt));
|
|
53
|
+
}
|
|
54
|
+
if (isPlainObject(obj)) {
|
|
55
|
+
const init = {};
|
|
56
|
+
for (const key in obj) {
|
|
57
|
+
init[key] = anyToCrdt(obj[key]);
|
|
58
|
+
}
|
|
59
|
+
return new LiveObject_1.LiveObject(init);
|
|
60
|
+
}
|
|
61
|
+
return obj;
|
|
62
|
+
}
|
|
63
|
+
function patchLiveList(liveList, prev, next) {
|
|
64
|
+
let i = 0;
|
|
65
|
+
let prevEnd = prev.length - 1;
|
|
66
|
+
let nextEnd = next.length - 1;
|
|
67
|
+
let prevNode = prev[0];
|
|
68
|
+
let nextNode = next[0];
|
|
69
|
+
/**
|
|
70
|
+
* For A,B,C => A,B,C,D
|
|
71
|
+
* i = 3, prevEnd = 2, nextEnd = 3
|
|
72
|
+
*
|
|
73
|
+
* For A,B,C => B,C
|
|
74
|
+
* i = 2, prevEnd = 2, nextEnd = 1
|
|
75
|
+
*
|
|
76
|
+
* For B,C => A,B,C
|
|
77
|
+
* i = 0, pre
|
|
78
|
+
*/
|
|
79
|
+
outer: {
|
|
80
|
+
while (prevNode === nextNode) {
|
|
81
|
+
++i;
|
|
82
|
+
if (i > prevEnd || i > nextEnd) {
|
|
83
|
+
break outer;
|
|
84
|
+
}
|
|
85
|
+
prevNode = prev[i];
|
|
86
|
+
nextNode = next[i];
|
|
87
|
+
}
|
|
88
|
+
prevNode = prev[prevEnd];
|
|
89
|
+
nextNode = next[nextEnd];
|
|
90
|
+
while (prevNode === nextNode) {
|
|
91
|
+
prevEnd--;
|
|
92
|
+
nextEnd--;
|
|
93
|
+
if (i > prevEnd || i > nextEnd) {
|
|
94
|
+
break outer;
|
|
95
|
+
}
|
|
96
|
+
prevNode = prev[prevEnd];
|
|
97
|
+
nextNode = next[nextEnd];
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
if (i > prevEnd) {
|
|
101
|
+
if (i <= nextEnd) {
|
|
102
|
+
while (i <= nextEnd) {
|
|
103
|
+
liveList.insert(anyToCrdt(next[i]), i);
|
|
104
|
+
i++;
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
else if (i > nextEnd) {
|
|
109
|
+
while (i <= prevEnd) {
|
|
110
|
+
liveList.delete(i++);
|
|
111
|
+
}
|
|
112
|
+
}
|
|
113
|
+
else {
|
|
114
|
+
while (i <= prevEnd && i <= nextEnd) {
|
|
115
|
+
prevNode = prev[i];
|
|
116
|
+
nextNode = next[i];
|
|
117
|
+
const liveListNode = liveList.get(i);
|
|
118
|
+
if (liveListNode instanceof LiveObject_1.LiveObject &&
|
|
119
|
+
isPlainObject(prevNode) &&
|
|
120
|
+
isPlainObject(nextNode)) {
|
|
121
|
+
patchLiveObject(liveListNode, prevNode, nextNode);
|
|
122
|
+
}
|
|
123
|
+
else {
|
|
124
|
+
liveList.delete(i);
|
|
125
|
+
liveList.insert(anyToCrdt(nextNode), i);
|
|
126
|
+
}
|
|
127
|
+
i++;
|
|
128
|
+
}
|
|
129
|
+
while (i <= nextEnd) {
|
|
130
|
+
liveList.insert(anyToCrdt(next[i]), i);
|
|
131
|
+
i++;
|
|
132
|
+
}
|
|
133
|
+
while (i <= prevEnd) {
|
|
134
|
+
liveList.delete(i);
|
|
135
|
+
i++;
|
|
136
|
+
}
|
|
137
|
+
}
|
|
138
|
+
}
|
|
139
|
+
exports.patchLiveList = patchLiveList;
|
|
140
|
+
function patchLiveObjectKey(liveObject, key, prev, next) {
|
|
141
|
+
const value = liveObject.get(key);
|
|
142
|
+
if (next === undefined) {
|
|
143
|
+
liveObject.delete(key);
|
|
144
|
+
}
|
|
145
|
+
else if (value === undefined) {
|
|
146
|
+
liveObject.set(key, anyToCrdt(next));
|
|
147
|
+
}
|
|
148
|
+
else if (prev === next) {
|
|
149
|
+
return;
|
|
150
|
+
}
|
|
151
|
+
else if (value instanceof LiveList_1.LiveList &&
|
|
152
|
+
Array.isArray(prev) &&
|
|
153
|
+
Array.isArray(next)) {
|
|
154
|
+
patchLiveList(value, prev, next);
|
|
155
|
+
}
|
|
156
|
+
else if (value instanceof LiveObject_1.LiveObject &&
|
|
157
|
+
isPlainObject(prev) &&
|
|
158
|
+
isPlainObject(next)) {
|
|
159
|
+
patchLiveObject(value, prev, next);
|
|
160
|
+
}
|
|
161
|
+
else {
|
|
162
|
+
liveObject.set(key, anyToCrdt(next));
|
|
163
|
+
}
|
|
164
|
+
}
|
|
165
|
+
exports.patchLiveObjectKey = patchLiveObjectKey;
|
|
166
|
+
function patchLiveObject(root, prev, next) {
|
|
167
|
+
const updates = {};
|
|
168
|
+
for (const key in next) {
|
|
169
|
+
patchLiveObjectKey(root, key, prev[key], next[key]);
|
|
170
|
+
}
|
|
171
|
+
for (const key in prev) {
|
|
172
|
+
if (next[key] === undefined) {
|
|
173
|
+
root.delete(key);
|
|
174
|
+
}
|
|
175
|
+
}
|
|
176
|
+
if (Object.keys(updates).length > 0) {
|
|
177
|
+
root.update(updates);
|
|
178
|
+
}
|
|
179
|
+
}
|
|
180
|
+
exports.patchLiveObject = patchLiveObject;
|
|
181
|
+
function getParentsPath(node) {
|
|
182
|
+
const path = [];
|
|
183
|
+
while (node._parentKey != null && node._parent != null) {
|
|
184
|
+
if (node._parent instanceof LiveList_1.LiveList) {
|
|
185
|
+
path.push(node._parent._indexOfPosition(node._parentKey));
|
|
186
|
+
}
|
|
187
|
+
else {
|
|
188
|
+
path.push(node._parentKey);
|
|
189
|
+
}
|
|
190
|
+
node = node._parent;
|
|
191
|
+
}
|
|
192
|
+
return path;
|
|
193
|
+
}
|
|
194
|
+
function patchImmutableObject(state, updates) {
|
|
195
|
+
return updates.reduce((state, update) => patchImmutableObjectWithUpdate(state, update), state);
|
|
196
|
+
}
|
|
197
|
+
exports.patchImmutableObject = patchImmutableObject;
|
|
198
|
+
function patchImmutableObjectWithUpdate(state, update) {
|
|
199
|
+
const path = getParentsPath(update.node);
|
|
200
|
+
return patchImmutableNode(state, path, update);
|
|
201
|
+
}
|
|
202
|
+
function patchImmutableNode(state, path, update) {
|
|
203
|
+
var _a, _b, _c, _d;
|
|
204
|
+
const pathItem = path.pop();
|
|
205
|
+
if (pathItem === undefined) {
|
|
206
|
+
switch (update.type) {
|
|
207
|
+
case "LiveObject": {
|
|
208
|
+
if (typeof state !== "object") {
|
|
209
|
+
throw new Error("Internal: received update on LiveObject but state was not an object");
|
|
210
|
+
}
|
|
211
|
+
let newState = Object.assign({}, state);
|
|
212
|
+
for (const key in update.updates) {
|
|
213
|
+
if (((_a = update.updates[key]) === null || _a === void 0 ? void 0 : _a.type) === "update") {
|
|
214
|
+
newState[key] = liveNodeToJson(update.node.get(key));
|
|
215
|
+
}
|
|
216
|
+
else if (((_b = update.updates[key]) === null || _b === void 0 ? void 0 : _b.type) === "delete") {
|
|
217
|
+
delete newState[key];
|
|
218
|
+
}
|
|
219
|
+
}
|
|
220
|
+
return newState;
|
|
221
|
+
}
|
|
222
|
+
case "LiveList": {
|
|
223
|
+
if (Array.isArray(state) === false) {
|
|
224
|
+
throw new Error("Internal: received update on LiveList but state was not an array");
|
|
225
|
+
}
|
|
226
|
+
let newState = state.map((x) => x);
|
|
227
|
+
const newArray = update.node.toArray();
|
|
228
|
+
for (const listUpdate of update.updates) {
|
|
229
|
+
if (listUpdate.type === "insert") {
|
|
230
|
+
if (listUpdate.index === newState.length) {
|
|
231
|
+
newState.push(liveNodeToJson(newArray[listUpdate.index]));
|
|
232
|
+
}
|
|
233
|
+
else {
|
|
234
|
+
newState = [
|
|
235
|
+
...newState.slice(0, listUpdate.index),
|
|
236
|
+
liveNodeToJson(newArray[listUpdate.index]),
|
|
237
|
+
...newState.slice(listUpdate.index),
|
|
238
|
+
];
|
|
239
|
+
}
|
|
240
|
+
}
|
|
241
|
+
else if (listUpdate.type === "delete") {
|
|
242
|
+
newState.splice(listUpdate.index, 1);
|
|
243
|
+
}
|
|
244
|
+
}
|
|
245
|
+
return newState;
|
|
246
|
+
}
|
|
247
|
+
case "LiveMap": {
|
|
248
|
+
if (typeof state !== "object") {
|
|
249
|
+
throw new Error("Internal: received update on LiveMap but state was not an object");
|
|
250
|
+
}
|
|
251
|
+
let newState = Object.assign({}, state);
|
|
252
|
+
for (const key in update.updates) {
|
|
253
|
+
if (((_c = update.updates[key]) === null || _c === void 0 ? void 0 : _c.type) === "update") {
|
|
254
|
+
newState[key] = liveNodeToJson(update.node.get(key));
|
|
255
|
+
}
|
|
256
|
+
else if (((_d = update.updates[key]) === null || _d === void 0 ? void 0 : _d.type) === "delete") {
|
|
257
|
+
delete newState[key];
|
|
258
|
+
}
|
|
259
|
+
}
|
|
260
|
+
return newState;
|
|
261
|
+
}
|
|
262
|
+
}
|
|
263
|
+
}
|
|
264
|
+
if (Array.isArray(state)) {
|
|
265
|
+
const newArray = [...state];
|
|
266
|
+
newArray[pathItem] = patchImmutableNode(state[pathItem], path, update);
|
|
267
|
+
return newArray;
|
|
268
|
+
}
|
|
269
|
+
else {
|
|
270
|
+
return Object.assign(Object.assign({}, state), { [pathItem]: patchImmutableNode(state[pathItem], path, update) });
|
|
271
|
+
}
|
|
272
|
+
}
|
package/lib/cjs/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/cjs/index.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.createClient = exports.LiveList = exports.LiveMap = exports.LiveObject = void 0;
|
|
3
|
+
exports.patchLiveObjectKey = exports.patchLiveObject = exports.patchImmutableObject = exports.patchLiveList = exports.liveNodeToJson = exports.liveObjectToJson = exports.createClient = exports.LiveList = exports.LiveMap = exports.LiveObject = void 0;
|
|
4
4
|
var LiveObject_1 = require("./LiveObject");
|
|
5
5
|
Object.defineProperty(exports, "LiveObject", { enumerable: true, get: function () { return LiveObject_1.LiveObject; } });
|
|
6
6
|
var LiveMap_1 = require("./LiveMap");
|
|
@@ -9,3 +9,10 @@ var LiveList_1 = require("./LiveList");
|
|
|
9
9
|
Object.defineProperty(exports, "LiveList", { enumerable: true, get: function () { return LiveList_1.LiveList; } });
|
|
10
10
|
var client_1 = require("./client");
|
|
11
11
|
Object.defineProperty(exports, "createClient", { enumerable: true, get: function () { return client_1.createClient; } });
|
|
12
|
+
var immutable_1 = require("./immutable");
|
|
13
|
+
Object.defineProperty(exports, "liveObjectToJson", { enumerable: true, get: function () { return immutable_1.liveObjectToJson; } });
|
|
14
|
+
Object.defineProperty(exports, "liveNodeToJson", { enumerable: true, get: function () { return immutable_1.liveNodeToJson; } });
|
|
15
|
+
Object.defineProperty(exports, "patchLiveList", { enumerable: true, get: function () { return immutable_1.patchLiveList; } });
|
|
16
|
+
Object.defineProperty(exports, "patchImmutableObject", { enumerable: true, get: function () { return immutable_1.patchImmutableObject; } });
|
|
17
|
+
Object.defineProperty(exports, "patchLiveObject", { enumerable: true, get: function () { return immutable_1.patchLiveObject; } });
|
|
18
|
+
Object.defineProperty(exports, "patchLiveObjectKey", { enumerable: true, get: function () { return immutable_1.patchLiveObjectKey; } });
|
package/lib/cjs/room.d.ts
CHANGED
package/lib/cjs/room.js
CHANGED
|
@@ -215,22 +215,22 @@ function makeStateMachine(state, context, mockedEffects) {
|
|
|
215
215
|
state.undoStack.push(historyItem);
|
|
216
216
|
}
|
|
217
217
|
}
|
|
218
|
-
function storageDispatch(ops, reverse,
|
|
218
|
+
function storageDispatch(ops, reverse, storageUpdates) {
|
|
219
219
|
if (state.isBatching) {
|
|
220
220
|
state.batch.ops.push(...ops);
|
|
221
|
-
|
|
222
|
-
state.batch.updates.
|
|
223
|
-
}
|
|
221
|
+
storageUpdates.forEach((value, key) => {
|
|
222
|
+
state.batch.updates.storageUpdates.set(key, (0, utils_1.mergeStorageUpdates)(state.batch.updates.storageUpdates.get(key), value));
|
|
223
|
+
});
|
|
224
224
|
state.batch.reverseOps.push(...reverse);
|
|
225
225
|
}
|
|
226
226
|
else {
|
|
227
227
|
addToUndoStack(reverse);
|
|
228
228
|
state.redoStack = [];
|
|
229
229
|
dispatch(ops);
|
|
230
|
-
notify({
|
|
230
|
+
notify({ storageUpdates: storageUpdates });
|
|
231
231
|
}
|
|
232
232
|
}
|
|
233
|
-
function notify({
|
|
233
|
+
function notify({ storageUpdates = new Map(), presence = false, others = [], }) {
|
|
234
234
|
if (others.length > 0) {
|
|
235
235
|
state.others = makeOthers(state.users);
|
|
236
236
|
for (const event of others) {
|
|
@@ -244,28 +244,9 @@ function makeStateMachine(state, context, mockedEffects) {
|
|
|
244
244
|
listener(state.me);
|
|
245
245
|
}
|
|
246
246
|
}
|
|
247
|
-
if (
|
|
247
|
+
if (storageUpdates.size > 0) {
|
|
248
248
|
for (const subscriber of state.listeners.storage) {
|
|
249
|
-
subscriber(Array.from(
|
|
250
|
-
if (m instanceof LiveObject_1.LiveObject) {
|
|
251
|
-
return {
|
|
252
|
-
type: "LiveObject",
|
|
253
|
-
node: m,
|
|
254
|
-
};
|
|
255
|
-
}
|
|
256
|
-
else if (m instanceof LiveList_1.LiveList) {
|
|
257
|
-
return {
|
|
258
|
-
type: "LiveList",
|
|
259
|
-
node: m,
|
|
260
|
-
};
|
|
261
|
-
}
|
|
262
|
-
else {
|
|
263
|
-
return {
|
|
264
|
-
type: "LiveMap",
|
|
265
|
-
node: m,
|
|
266
|
-
};
|
|
267
|
-
}
|
|
268
|
-
}));
|
|
249
|
+
subscriber(Array.from(storageUpdates.values()));
|
|
269
250
|
}
|
|
270
251
|
}
|
|
271
252
|
}
|
|
@@ -288,7 +269,10 @@ function makeStateMachine(state, context, mockedEffects) {
|
|
|
288
269
|
function apply(item, isLocal) {
|
|
289
270
|
const result = {
|
|
290
271
|
reverse: [],
|
|
291
|
-
updates: {
|
|
272
|
+
updates: {
|
|
273
|
+
storageUpdates: new Map(),
|
|
274
|
+
presence: false,
|
|
275
|
+
},
|
|
292
276
|
};
|
|
293
277
|
for (const op of item) {
|
|
294
278
|
if (op.type === "presence") {
|
|
@@ -318,7 +302,7 @@ function makeStateMachine(state, context, mockedEffects) {
|
|
|
318
302
|
}
|
|
319
303
|
const applyOpResult = applyOp(op, isLocal);
|
|
320
304
|
if (applyOpResult.modified) {
|
|
321
|
-
result.updates.
|
|
305
|
+
result.updates.storageUpdates.set(applyOpResult.modified.node._id, (0, utils_1.mergeStorageUpdates)(result.updates.storageUpdates.get(applyOpResult.modified.node._id), applyOpResult.modified));
|
|
322
306
|
result.reverse.unshift(...applyOpResult.reverse);
|
|
323
307
|
}
|
|
324
308
|
}
|
|
@@ -346,17 +330,12 @@ function makeStateMachine(state, context, mockedEffects) {
|
|
|
346
330
|
}
|
|
347
331
|
if (item._parent instanceof LiveList_1.LiveList) {
|
|
348
332
|
const previousKey = item._parentKey;
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
parentKey: previousKey,
|
|
356
|
-
},
|
|
357
|
-
],
|
|
358
|
-
modified: item._parent,
|
|
359
|
-
};
|
|
333
|
+
if (previousKey === op.parentKey) {
|
|
334
|
+
return { modified: false };
|
|
335
|
+
}
|
|
336
|
+
else {
|
|
337
|
+
return item._parent._setChildKey(op.parentKey, item, previousKey);
|
|
338
|
+
}
|
|
360
339
|
}
|
|
361
340
|
return { modified: false };
|
|
362
341
|
}
|
|
@@ -579,7 +558,7 @@ See v0.13 release notes for more information.
|
|
|
579
558
|
subMessages.push(message);
|
|
580
559
|
}
|
|
581
560
|
const updates = {
|
|
582
|
-
|
|
561
|
+
storageUpdates: new Map(),
|
|
583
562
|
others: [],
|
|
584
563
|
};
|
|
585
564
|
for (const subMessage of subMessages) {
|
|
@@ -615,9 +594,9 @@ See v0.13 release notes for more information.
|
|
|
615
594
|
}
|
|
616
595
|
case live_1.ServerMessageType.UpdateStorage: {
|
|
617
596
|
const applyResult = apply(subMessage.ops, false);
|
|
618
|
-
|
|
619
|
-
updates.
|
|
620
|
-
}
|
|
597
|
+
applyResult.updates.storageUpdates.forEach((value, key) => {
|
|
598
|
+
updates.storageUpdates.set(key, (0, utils_1.mergeStorageUpdates)(updates.storageUpdates.get(key), value));
|
|
599
|
+
});
|
|
621
600
|
break;
|
|
622
601
|
}
|
|
623
602
|
}
|
|
@@ -911,8 +890,11 @@ See v0.13 release notes for more information.
|
|
|
911
890
|
if (state.batch.reverseOps.length > 0) {
|
|
912
891
|
addToUndoStack(state.batch.reverseOps);
|
|
913
892
|
}
|
|
914
|
-
|
|
915
|
-
|
|
893
|
+
if (state.batch.ops.length > 0) {
|
|
894
|
+
// Only clear the redo stack if something has changed during a batch
|
|
895
|
+
// Clear the redo stack because batch is always called from a local operation
|
|
896
|
+
state.redoStack = [];
|
|
897
|
+
}
|
|
916
898
|
if (state.batch.ops.length > 0) {
|
|
917
899
|
dispatch(state.batch.ops);
|
|
918
900
|
}
|
|
@@ -922,7 +904,7 @@ See v0.13 release notes for more information.
|
|
|
922
904
|
reverseOps: [],
|
|
923
905
|
updates: {
|
|
924
906
|
others: [],
|
|
925
|
-
|
|
907
|
+
storageUpdates: new Map(),
|
|
926
908
|
presence: false,
|
|
927
909
|
},
|
|
928
910
|
};
|
|
@@ -1035,7 +1017,11 @@ function defaultState(me, defaultStorageRoot) {
|
|
|
1035
1017
|
isBatching: false,
|
|
1036
1018
|
batch: {
|
|
1037
1019
|
ops: [],
|
|
1038
|
-
updates: {
|
|
1020
|
+
updates: {
|
|
1021
|
+
storageUpdates: new Map(),
|
|
1022
|
+
presence: false,
|
|
1023
|
+
others: [],
|
|
1024
|
+
},
|
|
1039
1025
|
reverseOps: [],
|
|
1040
1026
|
},
|
|
1041
1027
|
offlineOperations: new Map(),
|
package/lib/cjs/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/cjs/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/cjs/utils.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.getTreesDiffOperations = exports.selfOrRegister = exports.selfOrRegisterValue = exports.isCrdt = exports.deserialize = exports.isSameNodeOrChildOf = exports.remove = void 0;
|
|
3
|
+
exports.mergeStorageUpdates = 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");
|
|
@@ -148,3 +148,28 @@ function getTreesDiffOperations(currentItems, newItems) {
|
|
|
148
148
|
return ops;
|
|
149
149
|
}
|
|
150
150
|
exports.getTreesDiffOperations = getTreesDiffOperations;
|
|
151
|
+
function mergeStorageUpdates(first, second) {
|
|
152
|
+
if (!first) {
|
|
153
|
+
return second;
|
|
154
|
+
}
|
|
155
|
+
if (second.type === "LiveObject") {
|
|
156
|
+
const updates = first.updates;
|
|
157
|
+
for (const [key, value] of Object.entries(second.updates)) {
|
|
158
|
+
updates[key] = value;
|
|
159
|
+
}
|
|
160
|
+
return Object.assign(Object.assign({}, second), { updates: updates });
|
|
161
|
+
}
|
|
162
|
+
else if (second.type === "LiveMap") {
|
|
163
|
+
const updates = first.updates;
|
|
164
|
+
for (const [key, value] of Object.entries(second.updates)) {
|
|
165
|
+
updates[key] = value;
|
|
166
|
+
}
|
|
167
|
+
return Object.assign(Object.assign({}, second), { updates: updates });
|
|
168
|
+
}
|
|
169
|
+
else if (second.type === "LiveList") {
|
|
170
|
+
const updates = first.updates;
|
|
171
|
+
return Object.assign(Object.assign({}, second), { updates: updates.concat(second.updates) });
|
|
172
|
+
}
|
|
173
|
+
return second;
|
|
174
|
+
}
|
|
175
|
+
exports.mergeStorageUpdates = mergeStorageUpdates;
|
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
import { Op, SerializedCrdt } from "./live";
|
|
2
|
+
import { StorageUpdate } from "./types";
|
|
2
3
|
export declare type ApplyResult = {
|
|
3
4
|
reverse: Op[];
|
|
4
|
-
modified:
|
|
5
|
+
modified: StorageUpdate;
|
|
5
6
|
} | {
|
|
6
7
|
modified: false;
|
|
7
8
|
};
|
|
@@ -10,7 +11,7 @@ export interface Doc {
|
|
|
10
11
|
generateOpId: () => string;
|
|
11
12
|
addItem: (id: string, item: AbstractCrdt) => void;
|
|
12
13
|
deleteItem: (id: string) => void;
|
|
13
|
-
dispatch: (ops: Op[], reverseOps: Op[],
|
|
14
|
+
dispatch: (ops: Op[], reverseOps: Op[], storageUpdates: Map<string, StorageUpdate>) => void;
|
|
14
15
|
}
|
|
15
16
|
export declare abstract class AbstractCrdt {
|
|
16
17
|
#private;
|
|
@@ -53,7 +54,7 @@ export declare abstract class AbstractCrdt {
|
|
|
53
54
|
/**
|
|
54
55
|
* INTERNAL
|
|
55
56
|
*/
|
|
56
|
-
abstract _detachChild(crdt: AbstractCrdt):
|
|
57
|
+
abstract _detachChild(crdt: AbstractCrdt): ApplyResult;
|
|
57
58
|
/**
|
|
58
59
|
* INTERNAL
|
|
59
60
|
*/
|
|
@@ -62,4 +63,5 @@ export declare abstract class AbstractCrdt {
|
|
|
62
63
|
* INTERNAL
|
|
63
64
|
*/
|
|
64
65
|
abstract _toSerializedCrdt(): SerializedCrdt;
|
|
66
|
+
abstract _getType(): string;
|
|
65
67
|
}
|
package/lib/esm/AbstractCrdt.js
CHANGED
|
@@ -49,10 +49,7 @@ export class AbstractCrdt {
|
|
|
49
49
|
switch (op.type) {
|
|
50
50
|
case OpType.DeleteCrdt: {
|
|
51
51
|
if (this._parent != null && this._parentKey != null) {
|
|
52
|
-
|
|
53
|
-
const reverse = this._serialize(this._parent._id, this._parentKey, __classPrivateFieldGet(this, _AbstractCrdt_doc, "f"));
|
|
54
|
-
this._parent._detachChild(this);
|
|
55
|
-
return { modified: parent, reverse };
|
|
52
|
+
return this._parent._detachChild(this);
|
|
56
53
|
}
|
|
57
54
|
return { modified: false };
|
|
58
55
|
}
|
package/lib/esm/LiveList.d.ts
CHANGED
|
@@ -14,6 +14,7 @@ export declare class LiveList<T> extends AbstractCrdt {
|
|
|
14
14
|
* INTERNAL
|
|
15
15
|
*/
|
|
16
16
|
_serialize(parentId?: string, parentKey?: string, doc?: Doc): Op[];
|
|
17
|
+
_indexOfPosition(position: string): number;
|
|
17
18
|
/**
|
|
18
19
|
* INTERNAL
|
|
19
20
|
*/
|
|
@@ -29,15 +30,19 @@ export declare class LiveList<T> extends AbstractCrdt {
|
|
|
29
30
|
/**
|
|
30
31
|
* INTERNAL
|
|
31
32
|
*/
|
|
32
|
-
_detachChild(child: AbstractCrdt):
|
|
33
|
+
_detachChild(child: AbstractCrdt): ApplyResult;
|
|
33
34
|
/**
|
|
34
35
|
* INTERNAL
|
|
35
36
|
*/
|
|
36
|
-
_setChildKey(key: string, child: AbstractCrdt):
|
|
37
|
+
_setChildKey(key: string, child: AbstractCrdt, previousKey: string): ApplyResult;
|
|
37
38
|
/**
|
|
38
39
|
* INTERNAL
|
|
39
40
|
*/
|
|
40
41
|
_apply(op: Op, isLocal: boolean): ApplyResult;
|
|
42
|
+
/**
|
|
43
|
+
* INTERNAL
|
|
44
|
+
*/
|
|
45
|
+
_getType(): string;
|
|
41
46
|
/**
|
|
42
47
|
* INTERNAL
|
|
43
48
|
*/
|
|
@@ -73,6 +78,7 @@ export declare class LiveList<T> extends AbstractCrdt {
|
|
|
73
78
|
* Returns an Array of all the elements in the LiveList.
|
|
74
79
|
*/
|
|
75
80
|
toArray(): T[];
|
|
81
|
+
toCrdtArray(): AbstractCrdt[];
|
|
76
82
|
/**
|
|
77
83
|
* Tests whether all elements pass the test implemented by the provided function.
|
|
78
84
|
* @param predicate Function to test for each element, taking two arguments (the element and its index).
|