@liveblocks/client 0.14.1 → 0.14.4
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 +2 -1
- package/lib/cjs/LiveList.d.ts +1 -1
- package/lib/cjs/LiveList.js +4 -1
- package/lib/cjs/LiveMap.d.ts +1 -1
- package/lib/cjs/LiveMap.js +4 -1
- package/lib/cjs/LiveObject.d.ts +1 -1
- package/lib/cjs/LiveObject.js +35 -3
- package/lib/cjs/LiveRegister.d.ts +1 -1
- package/lib/cjs/LiveRegister.js +1 -1
- package/lib/cjs/room.js +15 -8
- package/lib/cjs/types.d.ts +4 -0
- package/lib/esm/AbstractCrdt.d.ts +2 -1
- package/lib/esm/LiveList.d.ts +1 -1
- package/lib/esm/LiveList.js +4 -1
- package/lib/esm/LiveMap.d.ts +1 -1
- package/lib/esm/LiveMap.js +4 -1
- package/lib/esm/LiveObject.d.ts +1 -1
- package/lib/esm/LiveObject.js +35 -3
- package/lib/esm/LiveRegister.d.ts +1 -1
- package/lib/esm/LiveRegister.js +1 -1
- package/lib/esm/room.js +15 -8
- package/lib/esm/types.d.ts +4 -0
- package/package.json +2 -2
- package/lib/cjs/authentication.d.ts +0 -3
- package/lib/cjs/authentication.js +0 -71
- package/lib/cjs/immutable.d.ts +0 -9
- package/lib/cjs/immutable.js +0 -291
- package/lib/esm/authentication.d.ts +0 -3
- package/lib/esm/authentication.js +0 -66
- package/lib/esm/immutable.d.ts +0 -9
- package/lib/esm/immutable.js +0 -282
|
@@ -8,6 +8,7 @@ export declare type ApplyResult = {
|
|
|
8
8
|
export interface Doc {
|
|
9
9
|
generateId: () => string;
|
|
10
10
|
generateOpId: () => string;
|
|
11
|
+
getItem: (id: string) => AbstractCrdt | undefined;
|
|
11
12
|
addItem: (id: string, item: AbstractCrdt) => void;
|
|
12
13
|
deleteItem: (id: string) => void;
|
|
13
14
|
dispatch: (ops: Op[], reverseOps: Op[], modified: AbstractCrdt[]) => void;
|
|
@@ -45,7 +46,7 @@ export declare abstract class AbstractCrdt {
|
|
|
45
46
|
/**
|
|
46
47
|
* INTERNAL
|
|
47
48
|
*/
|
|
48
|
-
abstract _attachChild(id: string, key: string, crdt: AbstractCrdt, isLocal: boolean): ApplyResult;
|
|
49
|
+
abstract _attachChild(id: string, key: string, crdt: AbstractCrdt, opId: string, isLocal: boolean): ApplyResult;
|
|
49
50
|
/**
|
|
50
51
|
* INTERNAL
|
|
51
52
|
*/
|
package/lib/cjs/LiveList.d.ts
CHANGED
|
@@ -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, isLocal: boolean): ApplyResult;
|
|
28
|
+
_attachChild(id: string, key: string, child: AbstractCrdt, opId: string, isLocal: boolean): ApplyResult;
|
|
29
29
|
/**
|
|
30
30
|
* INTERNAL
|
|
31
31
|
*/
|
package/lib/cjs/LiveList.js
CHANGED
|
@@ -96,11 +96,14 @@ class LiveList extends AbstractCrdt_1.AbstractCrdt {
|
|
|
96
96
|
/**
|
|
97
97
|
* INTERNAL
|
|
98
98
|
*/
|
|
99
|
-
_attachChild(id, key, child, isLocal) {
|
|
99
|
+
_attachChild(id, key, child, opId, isLocal) {
|
|
100
100
|
var _a;
|
|
101
101
|
if (this._doc == null) {
|
|
102
102
|
throw new Error("Can't attach child if doc is not present");
|
|
103
103
|
}
|
|
104
|
+
if (this._doc.getItem(id) !== undefined) {
|
|
105
|
+
return { modified: false };
|
|
106
|
+
}
|
|
104
107
|
child._attach(id, this._doc);
|
|
105
108
|
child._setParentLink(this, key);
|
|
106
109
|
const index = __classPrivateFieldGet(this, _LiveList_items, "f").findIndex((entry) => entry[1] === key);
|
package/lib/cjs/LiveMap.d.ts
CHANGED
|
@@ -23,7 +23,7 @@ export declare class LiveMap<TKey extends string, TValue> extends AbstractCrdt {
|
|
|
23
23
|
/**
|
|
24
24
|
* INTERNAL
|
|
25
25
|
*/
|
|
26
|
-
_attachChild(id: string, key: TKey, child: AbstractCrdt, isLocal: boolean): ApplyResult;
|
|
26
|
+
_attachChild(id: string, key: TKey, child: AbstractCrdt, opId: string, isLocal: boolean): ApplyResult;
|
|
27
27
|
/**
|
|
28
28
|
* INTERNAL
|
|
29
29
|
*/
|
package/lib/cjs/LiveMap.js
CHANGED
|
@@ -100,10 +100,13 @@ class LiveMap extends AbstractCrdt_1.AbstractCrdt {
|
|
|
100
100
|
/**
|
|
101
101
|
* INTERNAL
|
|
102
102
|
*/
|
|
103
|
-
_attachChild(id, key, child, isLocal) {
|
|
103
|
+
_attachChild(id, key, child, opId, isLocal) {
|
|
104
104
|
if (this._doc == null) {
|
|
105
105
|
throw new Error("Can't attach child if doc is not present");
|
|
106
106
|
}
|
|
107
|
+
if (this._doc.getItem(id) !== undefined) {
|
|
108
|
+
return { modified: false };
|
|
109
|
+
}
|
|
107
110
|
const previousValue = __classPrivateFieldGet(this, _LiveMap_map, "f").get(key);
|
|
108
111
|
let reverse;
|
|
109
112
|
if (previousValue) {
|
package/lib/cjs/LiveObject.d.ts
CHANGED
|
@@ -27,7 +27,7 @@ export declare class LiveObject<T extends Record<string, any> = Record<string, a
|
|
|
27
27
|
/**
|
|
28
28
|
* INTERNAL
|
|
29
29
|
*/
|
|
30
|
-
_attachChild(id: string, key: keyof T, child: AbstractCrdt, isLocal: boolean): ApplyResult;
|
|
30
|
+
_attachChild(id: string, key: keyof T, child: AbstractCrdt, opId: string, isLocal: boolean): ApplyResult;
|
|
31
31
|
/**
|
|
32
32
|
* INTERNAL
|
|
33
33
|
*/
|
package/lib/cjs/LiveObject.js
CHANGED
|
@@ -106,10 +106,32 @@ class LiveObject extends AbstractCrdt_1.AbstractCrdt {
|
|
|
106
106
|
/**
|
|
107
107
|
* INTERNAL
|
|
108
108
|
*/
|
|
109
|
-
_attachChild(id, key, child, isLocal) {
|
|
109
|
+
_attachChild(id, key, child, opId, isLocal) {
|
|
110
110
|
if (this._doc == null) {
|
|
111
111
|
throw new Error("Can't attach child if doc is not present");
|
|
112
112
|
}
|
|
113
|
+
if (this._doc.getItem(id) !== undefined) {
|
|
114
|
+
if (__classPrivateFieldGet(this, _LiveObject_propToLastUpdate, "f").get(key) === opId) {
|
|
115
|
+
// Acknowlegment from local operation
|
|
116
|
+
__classPrivateFieldGet(this, _LiveObject_propToLastUpdate, "f").delete(key);
|
|
117
|
+
}
|
|
118
|
+
return { modified: false };
|
|
119
|
+
}
|
|
120
|
+
if (isLocal) {
|
|
121
|
+
__classPrivateFieldGet(this, _LiveObject_propToLastUpdate, "f").set(key, opId);
|
|
122
|
+
}
|
|
123
|
+
else if (__classPrivateFieldGet(this, _LiveObject_propToLastUpdate, "f").get(key) === undefined) {
|
|
124
|
+
// Remote operation with no local change => apply operation
|
|
125
|
+
}
|
|
126
|
+
else if (__classPrivateFieldGet(this, _LiveObject_propToLastUpdate, "f").get(key) === opId) {
|
|
127
|
+
// Acknowlegment from local operation
|
|
128
|
+
__classPrivateFieldGet(this, _LiveObject_propToLastUpdate, "f").delete(key);
|
|
129
|
+
return { modified: false };
|
|
130
|
+
}
|
|
131
|
+
else {
|
|
132
|
+
// Conflict, ignore remote operation
|
|
133
|
+
return { modified: false };
|
|
134
|
+
}
|
|
113
135
|
const previousValue = __classPrivateFieldGet(this, _LiveObject_map, "f").get(key);
|
|
114
136
|
let reverse;
|
|
115
137
|
if ((0, utils_1.isCrdt)(previousValue)) {
|
|
@@ -284,7 +306,6 @@ class LiveObject extends AbstractCrdt_1.AbstractCrdt {
|
|
|
284
306
|
data: {},
|
|
285
307
|
};
|
|
286
308
|
for (const key in overrides) {
|
|
287
|
-
__classPrivateFieldGet(this, _LiveObject_propToLastUpdate, "f").set(key, opId);
|
|
288
309
|
const oldValue = __classPrivateFieldGet(this, _LiveObject_map, "f").get(key);
|
|
289
310
|
if (oldValue instanceof AbstractCrdt_1.AbstractCrdt) {
|
|
290
311
|
reverseOps.push(...oldValue._serialize(this._id, key));
|
|
@@ -300,10 +321,16 @@ class LiveObject extends AbstractCrdt_1.AbstractCrdt {
|
|
|
300
321
|
if (newValue instanceof AbstractCrdt_1.AbstractCrdt) {
|
|
301
322
|
newValue._setParentLink(this, key);
|
|
302
323
|
newValue._attach(this._doc.generateId(), this._doc);
|
|
303
|
-
|
|
324
|
+
const newAttachChildOps = newValue._serialize(this._id, key, this._doc);
|
|
325
|
+
const createCrdtOp = newAttachChildOps.find((op) => op.parentId === this._id);
|
|
326
|
+
if (createCrdtOp) {
|
|
327
|
+
__classPrivateFieldGet(this, _LiveObject_propToLastUpdate, "f").set(key, createCrdtOp.opId);
|
|
328
|
+
}
|
|
329
|
+
ops.push(...newAttachChildOps);
|
|
304
330
|
}
|
|
305
331
|
else {
|
|
306
332
|
updatedProps[key] = newValue;
|
|
333
|
+
__classPrivateFieldGet(this, _LiveObject_propToLastUpdate, "f").set(key, opId);
|
|
307
334
|
}
|
|
308
335
|
__classPrivateFieldGet(this, _LiveObject_map, "f").set(key, newValue);
|
|
309
336
|
}
|
|
@@ -378,6 +405,11 @@ _LiveObject_map = new WeakMap(), _LiveObject_propToLastUpdate = new WeakMap(), _
|
|
|
378
405
|
if (__classPrivateFieldGet(this, _LiveObject_map, "f").has(key) === false) {
|
|
379
406
|
return { modified: false };
|
|
380
407
|
}
|
|
408
|
+
// If a local operation exists on the same key
|
|
409
|
+
// prevent flickering by not applying delete op.
|
|
410
|
+
if (__classPrivateFieldGet(this, _LiveObject_propToLastUpdate, "f").get(key) !== undefined) {
|
|
411
|
+
return { modified: false };
|
|
412
|
+
}
|
|
381
413
|
const oldValue = __classPrivateFieldGet(this, _LiveObject_map, "f").get(key);
|
|
382
414
|
let reverse = [];
|
|
383
415
|
if ((0, utils_1.isCrdt)(oldValue)) {
|
|
@@ -19,7 +19,7 @@ export declare class LiveRegister<TValue = any> extends AbstractCrdt {
|
|
|
19
19
|
* INTERNAL
|
|
20
20
|
*/
|
|
21
21
|
_toSerializedCrdt(): SerializedCrdt;
|
|
22
|
-
_attachChild(id: string, key: string, crdt: AbstractCrdt, isLocal: boolean): ApplyResult;
|
|
22
|
+
_attachChild(id: string, key: string, crdt: AbstractCrdt, opId: string, isLocal: boolean): ApplyResult;
|
|
23
23
|
_detachChild(crdt: AbstractCrdt): void;
|
|
24
24
|
_apply(op: Op, isLocal: boolean): ApplyResult;
|
|
25
25
|
}
|
package/lib/cjs/LiveRegister.js
CHANGED
package/lib/cjs/room.js
CHANGED
|
@@ -163,6 +163,7 @@ function makeStateMachine(state, context, mockedEffects) {
|
|
|
163
163
|
function load(items) {
|
|
164
164
|
const [root, parentToChildren] = buildRootAndParentToChildren(items);
|
|
165
165
|
return LiveObject_1.LiveObject._deserialize(root, parentToChildren, {
|
|
166
|
+
getItem,
|
|
166
167
|
addItem,
|
|
167
168
|
deleteItem,
|
|
168
169
|
generateId,
|
|
@@ -338,31 +339,31 @@ function makeStateMachine(state, context, mockedEffects) {
|
|
|
338
339
|
}
|
|
339
340
|
case live_1.OpType.CreateObject: {
|
|
340
341
|
const parent = state.items.get(op.parentId);
|
|
341
|
-
if (parent == null
|
|
342
|
+
if (parent == null) {
|
|
342
343
|
return { modified: false };
|
|
343
344
|
}
|
|
344
|
-
return parent._attachChild(op.id, op.parentKey, new LiveObject_1.LiveObject(op.data), isLocal);
|
|
345
|
+
return parent._attachChild(op.id, op.parentKey, new LiveObject_1.LiveObject(op.data), op.opId, isLocal);
|
|
345
346
|
}
|
|
346
347
|
case live_1.OpType.CreateList: {
|
|
347
348
|
const parent = state.items.get(op.parentId);
|
|
348
|
-
if (parent == null
|
|
349
|
+
if (parent == null) {
|
|
349
350
|
return { modified: false };
|
|
350
351
|
}
|
|
351
|
-
return parent._attachChild(op.id, op.parentKey, new LiveList_1.LiveList(), isLocal);
|
|
352
|
+
return parent._attachChild(op.id, op.parentKey, new LiveList_1.LiveList(), op.opId, isLocal);
|
|
352
353
|
}
|
|
353
354
|
case live_1.OpType.CreateRegister: {
|
|
354
355
|
const parent = state.items.get(op.parentId);
|
|
355
|
-
if (parent == null
|
|
356
|
+
if (parent == null) {
|
|
356
357
|
return { modified: false };
|
|
357
358
|
}
|
|
358
|
-
return parent._attachChild(op.id, op.parentKey, new LiveRegister_1.LiveRegister(op.data), isLocal);
|
|
359
|
+
return parent._attachChild(op.id, op.parentKey, new LiveRegister_1.LiveRegister(op.data), op.opId, isLocal);
|
|
359
360
|
}
|
|
360
361
|
case live_1.OpType.CreateMap: {
|
|
361
362
|
const parent = state.items.get(op.parentId);
|
|
362
|
-
if (parent == null
|
|
363
|
+
if (parent == null) {
|
|
363
364
|
return { modified: false };
|
|
364
365
|
}
|
|
365
|
-
return parent._attachChild(op.id, op.parentKey, new LiveMap_1.LiveMap(), isLocal);
|
|
366
|
+
return parent._attachChild(op.id, op.parentKey, new LiveMap_1.LiveMap(), op.opId, isLocal);
|
|
366
367
|
}
|
|
367
368
|
}
|
|
368
369
|
return { modified: false };
|
|
@@ -663,6 +664,11 @@ See v0.13 release notes for more information.
|
|
|
663
664
|
if (state.connection.state === "connecting") {
|
|
664
665
|
updateConnection(Object.assign(Object.assign({}, state.connection), { state: "open" }));
|
|
665
666
|
state.numberOfRetry = 0;
|
|
667
|
+
// Re-broadcast the user presence during a reconnect.
|
|
668
|
+
if (state.lastConnectionId !== undefined) {
|
|
669
|
+
state.buffer.presence = state.me;
|
|
670
|
+
tryFlushing();
|
|
671
|
+
}
|
|
666
672
|
state.lastConnectionId = state.connection.id;
|
|
667
673
|
if (state.root) {
|
|
668
674
|
state.buffer.messages.push({ type: live_1.ClientMessageType.FetchStorage });
|
|
@@ -1024,6 +1030,7 @@ function createRoom(options, context) {
|
|
|
1024
1030
|
const state = defaultState(options.defaultPresence, options.defaultStorageRoot);
|
|
1025
1031
|
const machine = makeStateMachine(state, context);
|
|
1026
1032
|
const room = {
|
|
1033
|
+
id: context.room,
|
|
1027
1034
|
/////////////
|
|
1028
1035
|
// Core //
|
|
1029
1036
|
/////////////
|
package/lib/cjs/types.d.ts
CHANGED
|
@@ -167,6 +167,10 @@ export declare type OthersEvent<T extends Presence = Presence> = {
|
|
|
167
167
|
type: "reset";
|
|
168
168
|
};
|
|
169
169
|
export declare type Room = {
|
|
170
|
+
/**
|
|
171
|
+
* The id of the room.
|
|
172
|
+
*/
|
|
173
|
+
readonly id: string;
|
|
170
174
|
getConnectionState(): ConnectionState;
|
|
171
175
|
subscribe: {
|
|
172
176
|
/**
|
|
@@ -8,6 +8,7 @@ export declare type ApplyResult = {
|
|
|
8
8
|
export interface Doc {
|
|
9
9
|
generateId: () => string;
|
|
10
10
|
generateOpId: () => string;
|
|
11
|
+
getItem: (id: string) => AbstractCrdt | undefined;
|
|
11
12
|
addItem: (id: string, item: AbstractCrdt) => void;
|
|
12
13
|
deleteItem: (id: string) => void;
|
|
13
14
|
dispatch: (ops: Op[], reverseOps: Op[], modified: AbstractCrdt[]) => void;
|
|
@@ -45,7 +46,7 @@ export declare abstract class AbstractCrdt {
|
|
|
45
46
|
/**
|
|
46
47
|
* INTERNAL
|
|
47
48
|
*/
|
|
48
|
-
abstract _attachChild(id: string, key: string, crdt: AbstractCrdt, isLocal: boolean): ApplyResult;
|
|
49
|
+
abstract _attachChild(id: string, key: string, crdt: AbstractCrdt, opId: string, isLocal: boolean): ApplyResult;
|
|
49
50
|
/**
|
|
50
51
|
* INTERNAL
|
|
51
52
|
*/
|
package/lib/esm/LiveList.d.ts
CHANGED
|
@@ -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, isLocal: boolean): ApplyResult;
|
|
28
|
+
_attachChild(id: string, key: string, child: AbstractCrdt, opId: string, isLocal: boolean): ApplyResult;
|
|
29
29
|
/**
|
|
30
30
|
* INTERNAL
|
|
31
31
|
*/
|
package/lib/esm/LiveList.js
CHANGED
|
@@ -93,11 +93,14 @@ export class LiveList extends AbstractCrdt {
|
|
|
93
93
|
/**
|
|
94
94
|
* INTERNAL
|
|
95
95
|
*/
|
|
96
|
-
_attachChild(id, key, child, isLocal) {
|
|
96
|
+
_attachChild(id, key, child, opId, isLocal) {
|
|
97
97
|
var _a;
|
|
98
98
|
if (this._doc == null) {
|
|
99
99
|
throw new Error("Can't attach child if doc is not present");
|
|
100
100
|
}
|
|
101
|
+
if (this._doc.getItem(id) !== undefined) {
|
|
102
|
+
return { modified: false };
|
|
103
|
+
}
|
|
101
104
|
child._attach(id, this._doc);
|
|
102
105
|
child._setParentLink(this, key);
|
|
103
106
|
const index = __classPrivateFieldGet(this, _LiveList_items, "f").findIndex((entry) => entry[1] === key);
|
package/lib/esm/LiveMap.d.ts
CHANGED
|
@@ -23,7 +23,7 @@ export declare class LiveMap<TKey extends string, TValue> extends AbstractCrdt {
|
|
|
23
23
|
/**
|
|
24
24
|
* INTERNAL
|
|
25
25
|
*/
|
|
26
|
-
_attachChild(id: string, key: TKey, child: AbstractCrdt, isLocal: boolean): ApplyResult;
|
|
26
|
+
_attachChild(id: string, key: TKey, child: AbstractCrdt, opId: string, isLocal: boolean): ApplyResult;
|
|
27
27
|
/**
|
|
28
28
|
* INTERNAL
|
|
29
29
|
*/
|
package/lib/esm/LiveMap.js
CHANGED
|
@@ -97,10 +97,13 @@ export class LiveMap extends AbstractCrdt {
|
|
|
97
97
|
/**
|
|
98
98
|
* INTERNAL
|
|
99
99
|
*/
|
|
100
|
-
_attachChild(id, key, child, isLocal) {
|
|
100
|
+
_attachChild(id, key, child, opId, isLocal) {
|
|
101
101
|
if (this._doc == null) {
|
|
102
102
|
throw new Error("Can't attach child if doc is not present");
|
|
103
103
|
}
|
|
104
|
+
if (this._doc.getItem(id) !== undefined) {
|
|
105
|
+
return { modified: false };
|
|
106
|
+
}
|
|
104
107
|
const previousValue = __classPrivateFieldGet(this, _LiveMap_map, "f").get(key);
|
|
105
108
|
let reverse;
|
|
106
109
|
if (previousValue) {
|
package/lib/esm/LiveObject.d.ts
CHANGED
|
@@ -27,7 +27,7 @@ export declare class LiveObject<T extends Record<string, any> = Record<string, a
|
|
|
27
27
|
/**
|
|
28
28
|
* INTERNAL
|
|
29
29
|
*/
|
|
30
|
-
_attachChild(id: string, key: keyof T, child: AbstractCrdt, isLocal: boolean): ApplyResult;
|
|
30
|
+
_attachChild(id: string, key: keyof T, child: AbstractCrdt, opId: string, isLocal: boolean): ApplyResult;
|
|
31
31
|
/**
|
|
32
32
|
* INTERNAL
|
|
33
33
|
*/
|
package/lib/esm/LiveObject.js
CHANGED
|
@@ -103,10 +103,32 @@ export class LiveObject extends AbstractCrdt {
|
|
|
103
103
|
/**
|
|
104
104
|
* INTERNAL
|
|
105
105
|
*/
|
|
106
|
-
_attachChild(id, key, child, isLocal) {
|
|
106
|
+
_attachChild(id, key, child, opId, isLocal) {
|
|
107
107
|
if (this._doc == null) {
|
|
108
108
|
throw new Error("Can't attach child if doc is not present");
|
|
109
109
|
}
|
|
110
|
+
if (this._doc.getItem(id) !== undefined) {
|
|
111
|
+
if (__classPrivateFieldGet(this, _LiveObject_propToLastUpdate, "f").get(key) === opId) {
|
|
112
|
+
// Acknowlegment from local operation
|
|
113
|
+
__classPrivateFieldGet(this, _LiveObject_propToLastUpdate, "f").delete(key);
|
|
114
|
+
}
|
|
115
|
+
return { modified: false };
|
|
116
|
+
}
|
|
117
|
+
if (isLocal) {
|
|
118
|
+
__classPrivateFieldGet(this, _LiveObject_propToLastUpdate, "f").set(key, opId);
|
|
119
|
+
}
|
|
120
|
+
else if (__classPrivateFieldGet(this, _LiveObject_propToLastUpdate, "f").get(key) === undefined) {
|
|
121
|
+
// Remote operation with no local change => apply operation
|
|
122
|
+
}
|
|
123
|
+
else if (__classPrivateFieldGet(this, _LiveObject_propToLastUpdate, "f").get(key) === opId) {
|
|
124
|
+
// Acknowlegment from local operation
|
|
125
|
+
__classPrivateFieldGet(this, _LiveObject_propToLastUpdate, "f").delete(key);
|
|
126
|
+
return { modified: false };
|
|
127
|
+
}
|
|
128
|
+
else {
|
|
129
|
+
// Conflict, ignore remote operation
|
|
130
|
+
return { modified: false };
|
|
131
|
+
}
|
|
110
132
|
const previousValue = __classPrivateFieldGet(this, _LiveObject_map, "f").get(key);
|
|
111
133
|
let reverse;
|
|
112
134
|
if (isCrdt(previousValue)) {
|
|
@@ -281,7 +303,6 @@ export class LiveObject extends AbstractCrdt {
|
|
|
281
303
|
data: {},
|
|
282
304
|
};
|
|
283
305
|
for (const key in overrides) {
|
|
284
|
-
__classPrivateFieldGet(this, _LiveObject_propToLastUpdate, "f").set(key, opId);
|
|
285
306
|
const oldValue = __classPrivateFieldGet(this, _LiveObject_map, "f").get(key);
|
|
286
307
|
if (oldValue instanceof AbstractCrdt) {
|
|
287
308
|
reverseOps.push(...oldValue._serialize(this._id, key));
|
|
@@ -297,10 +318,16 @@ export class LiveObject extends AbstractCrdt {
|
|
|
297
318
|
if (newValue instanceof AbstractCrdt) {
|
|
298
319
|
newValue._setParentLink(this, key);
|
|
299
320
|
newValue._attach(this._doc.generateId(), this._doc);
|
|
300
|
-
|
|
321
|
+
const newAttachChildOps = newValue._serialize(this._id, key, this._doc);
|
|
322
|
+
const createCrdtOp = newAttachChildOps.find((op) => op.parentId === this._id);
|
|
323
|
+
if (createCrdtOp) {
|
|
324
|
+
__classPrivateFieldGet(this, _LiveObject_propToLastUpdate, "f").set(key, createCrdtOp.opId);
|
|
325
|
+
}
|
|
326
|
+
ops.push(...newAttachChildOps);
|
|
301
327
|
}
|
|
302
328
|
else {
|
|
303
329
|
updatedProps[key] = newValue;
|
|
330
|
+
__classPrivateFieldGet(this, _LiveObject_propToLastUpdate, "f").set(key, opId);
|
|
304
331
|
}
|
|
305
332
|
__classPrivateFieldGet(this, _LiveObject_map, "f").set(key, newValue);
|
|
306
333
|
}
|
|
@@ -374,6 +401,11 @@ _LiveObject_map = new WeakMap(), _LiveObject_propToLastUpdate = new WeakMap(), _
|
|
|
374
401
|
if (__classPrivateFieldGet(this, _LiveObject_map, "f").has(key) === false) {
|
|
375
402
|
return { modified: false };
|
|
376
403
|
}
|
|
404
|
+
// If a local operation exists on the same key
|
|
405
|
+
// prevent flickering by not applying delete op.
|
|
406
|
+
if (__classPrivateFieldGet(this, _LiveObject_propToLastUpdate, "f").get(key) !== undefined) {
|
|
407
|
+
return { modified: false };
|
|
408
|
+
}
|
|
377
409
|
const oldValue = __classPrivateFieldGet(this, _LiveObject_map, "f").get(key);
|
|
378
410
|
let reverse = [];
|
|
379
411
|
if (isCrdt(oldValue)) {
|
|
@@ -19,7 +19,7 @@ export declare class LiveRegister<TValue = any> extends AbstractCrdt {
|
|
|
19
19
|
* INTERNAL
|
|
20
20
|
*/
|
|
21
21
|
_toSerializedCrdt(): SerializedCrdt;
|
|
22
|
-
_attachChild(id: string, key: string, crdt: AbstractCrdt, isLocal: boolean): ApplyResult;
|
|
22
|
+
_attachChild(id: string, key: string, crdt: AbstractCrdt, opId: string, isLocal: boolean): ApplyResult;
|
|
23
23
|
_detachChild(crdt: AbstractCrdt): void;
|
|
24
24
|
_apply(op: Op, isLocal: boolean): ApplyResult;
|
|
25
25
|
}
|
package/lib/esm/LiveRegister.js
CHANGED
package/lib/esm/room.js
CHANGED
|
@@ -160,6 +160,7 @@ export function makeStateMachine(state, context, mockedEffects) {
|
|
|
160
160
|
function load(items) {
|
|
161
161
|
const [root, parentToChildren] = buildRootAndParentToChildren(items);
|
|
162
162
|
return LiveObject._deserialize(root, parentToChildren, {
|
|
163
|
+
getItem,
|
|
163
164
|
addItem,
|
|
164
165
|
deleteItem,
|
|
165
166
|
generateId,
|
|
@@ -335,31 +336,31 @@ export function makeStateMachine(state, context, mockedEffects) {
|
|
|
335
336
|
}
|
|
336
337
|
case OpType.CreateObject: {
|
|
337
338
|
const parent = state.items.get(op.parentId);
|
|
338
|
-
if (parent == null
|
|
339
|
+
if (parent == null) {
|
|
339
340
|
return { modified: false };
|
|
340
341
|
}
|
|
341
|
-
return parent._attachChild(op.id, op.parentKey, new LiveObject(op.data), isLocal);
|
|
342
|
+
return parent._attachChild(op.id, op.parentKey, new LiveObject(op.data), op.opId, isLocal);
|
|
342
343
|
}
|
|
343
344
|
case OpType.CreateList: {
|
|
344
345
|
const parent = state.items.get(op.parentId);
|
|
345
|
-
if (parent == null
|
|
346
|
+
if (parent == null) {
|
|
346
347
|
return { modified: false };
|
|
347
348
|
}
|
|
348
|
-
return parent._attachChild(op.id, op.parentKey, new LiveList(), isLocal);
|
|
349
|
+
return parent._attachChild(op.id, op.parentKey, new LiveList(), op.opId, isLocal);
|
|
349
350
|
}
|
|
350
351
|
case OpType.CreateRegister: {
|
|
351
352
|
const parent = state.items.get(op.parentId);
|
|
352
|
-
if (parent == null
|
|
353
|
+
if (parent == null) {
|
|
353
354
|
return { modified: false };
|
|
354
355
|
}
|
|
355
|
-
return parent._attachChild(op.id, op.parentKey, new LiveRegister(op.data), isLocal);
|
|
356
|
+
return parent._attachChild(op.id, op.parentKey, new LiveRegister(op.data), op.opId, isLocal);
|
|
356
357
|
}
|
|
357
358
|
case OpType.CreateMap: {
|
|
358
359
|
const parent = state.items.get(op.parentId);
|
|
359
|
-
if (parent == null
|
|
360
|
+
if (parent == null) {
|
|
360
361
|
return { modified: false };
|
|
361
362
|
}
|
|
362
|
-
return parent._attachChild(op.id, op.parentKey, new LiveMap(), isLocal);
|
|
363
|
+
return parent._attachChild(op.id, op.parentKey, new LiveMap(), op.opId, isLocal);
|
|
363
364
|
}
|
|
364
365
|
}
|
|
365
366
|
return { modified: false };
|
|
@@ -660,6 +661,11 @@ See v0.13 release notes for more information.
|
|
|
660
661
|
if (state.connection.state === "connecting") {
|
|
661
662
|
updateConnection(Object.assign(Object.assign({}, state.connection), { state: "open" }));
|
|
662
663
|
state.numberOfRetry = 0;
|
|
664
|
+
// Re-broadcast the user presence during a reconnect.
|
|
665
|
+
if (state.lastConnectionId !== undefined) {
|
|
666
|
+
state.buffer.presence = state.me;
|
|
667
|
+
tryFlushing();
|
|
668
|
+
}
|
|
663
669
|
state.lastConnectionId = state.connection.id;
|
|
664
670
|
if (state.root) {
|
|
665
671
|
state.buffer.messages.push({ type: ClientMessageType.FetchStorage });
|
|
@@ -1019,6 +1025,7 @@ export function createRoom(options, context) {
|
|
|
1019
1025
|
const state = defaultState(options.defaultPresence, options.defaultStorageRoot);
|
|
1020
1026
|
const machine = makeStateMachine(state, context);
|
|
1021
1027
|
const room = {
|
|
1028
|
+
id: context.room,
|
|
1022
1029
|
/////////////
|
|
1023
1030
|
// Core //
|
|
1024
1031
|
/////////////
|
package/lib/esm/types.d.ts
CHANGED
|
@@ -167,6 +167,10 @@ export declare type OthersEvent<T extends Presence = Presence> = {
|
|
|
167
167
|
type: "reset";
|
|
168
168
|
};
|
|
169
169
|
export declare type Room = {
|
|
170
|
+
/**
|
|
171
|
+
* The id of the room.
|
|
172
|
+
*/
|
|
173
|
+
readonly id: string;
|
|
170
174
|
getConnectionState(): ConnectionState;
|
|
171
175
|
subscribe: {
|
|
172
176
|
/**
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@liveblocks/client",
|
|
3
|
-
"version": "0.14.
|
|
3
|
+
"version": "0.14.4",
|
|
4
4
|
"description": "",
|
|
5
5
|
"main": "./lib/cjs/index.js",
|
|
6
6
|
"module": "./lib/esm/index.js",
|
|
@@ -42,4 +42,4 @@
|
|
|
42
42
|
"url": "https://github.com/liveblocks/liveblocks.git",
|
|
43
43
|
"directory": "packages/liveblocks"
|
|
44
44
|
}
|
|
45
|
-
}
|
|
45
|
+
}
|
|
@@ -1,71 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
|
|
3
|
-
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
|
|
4
|
-
return new (P || (P = Promise))(function (resolve, reject) {
|
|
5
|
-
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
|
|
6
|
-
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
|
|
7
|
-
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
|
|
8
|
-
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
|
9
|
-
});
|
|
10
|
-
};
|
|
11
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
12
|
-
exports.parseToken = void 0;
|
|
13
|
-
function fetchAuthorize(endpoint, room, publicApiKey) {
|
|
14
|
-
return __awaiter(this, void 0, void 0, function* () {
|
|
15
|
-
const res = yield fetch(endpoint, {
|
|
16
|
-
method: "POST",
|
|
17
|
-
headers: {
|
|
18
|
-
"Content-Type": "application/json",
|
|
19
|
-
},
|
|
20
|
-
body: JSON.stringify({
|
|
21
|
-
room,
|
|
22
|
-
publicApiKey,
|
|
23
|
-
}),
|
|
24
|
-
});
|
|
25
|
-
if (!res.ok) {
|
|
26
|
-
throw new AuthenticationError(`Authentication error. Liveblocks could not parse the response of your authentication "${endpoint}"`);
|
|
27
|
-
}
|
|
28
|
-
let authResponse = null;
|
|
29
|
-
try {
|
|
30
|
-
authResponse = yield res.json();
|
|
31
|
-
}
|
|
32
|
-
catch (er) {
|
|
33
|
-
throw new AuthenticationError(`Authentication error. Liveblocks could not parse the response of your authentication "${endpoint}"`);
|
|
34
|
-
}
|
|
35
|
-
if (typeof authResponse.token !== "string") {
|
|
36
|
-
throw new AuthenticationError(`Authentication error. Liveblocks could not parse the response of your authentication "${endpoint}"`);
|
|
37
|
-
}
|
|
38
|
-
return authResponse.token;
|
|
39
|
-
});
|
|
40
|
-
}
|
|
41
|
-
function auth(endpoint, room, publicApiKey) {
|
|
42
|
-
return __awaiter(this, void 0, void 0, function* () {
|
|
43
|
-
if (typeof endpoint === "string") {
|
|
44
|
-
return fetchAuthorize(endpoint, room, publicApiKey);
|
|
45
|
-
}
|
|
46
|
-
if (typeof endpoint === "function") {
|
|
47
|
-
const { token } = yield endpoint(room);
|
|
48
|
-
// TODO: Validation
|
|
49
|
-
return token;
|
|
50
|
-
}
|
|
51
|
-
throw new Error("Authentication error. Liveblocks could not parse the response of your authentication endpoint");
|
|
52
|
-
});
|
|
53
|
-
}
|
|
54
|
-
exports.default = auth;
|
|
55
|
-
class AuthenticationError extends Error {
|
|
56
|
-
constructor(message) {
|
|
57
|
-
super(message);
|
|
58
|
-
}
|
|
59
|
-
}
|
|
60
|
-
function parseToken(token) {
|
|
61
|
-
const tokenParts = token.split(".");
|
|
62
|
-
if (tokenParts.length !== 3) {
|
|
63
|
-
throw new AuthenticationError(`Authentication error. Liveblocks could not parse the response of your authentication endpoint`);
|
|
64
|
-
}
|
|
65
|
-
const data = JSON.parse(atob(tokenParts[1]));
|
|
66
|
-
if (typeof data.actor !== "number") {
|
|
67
|
-
throw new AuthenticationError(`Authentication error. Liveblocks could not parse the response of your authentication endpoint`);
|
|
68
|
-
}
|
|
69
|
-
return data;
|
|
70
|
-
}
|
|
71
|
-
exports.parseToken = parseToken;
|
package/lib/cjs/immutable.d.ts
DELETED
|
@@ -1,9 +0,0 @@
|
|
|
1
|
-
import { LiveList } from "./LiveList";
|
|
2
|
-
import { LiveObject } from "./LiveObject";
|
|
3
|
-
import { StorageUpdate } from "./types";
|
|
4
|
-
export declare function liveObjectToJson(liveObject: LiveObject<any>): any;
|
|
5
|
-
export declare function liveNodeToJson(value: any): any;
|
|
6
|
-
export declare function patchLiveList<T>(liveList: LiveList<T>, prev: Array<T>, next: Array<T>): void;
|
|
7
|
-
export declare function patchLiveObjectKey<T>(liveObject: LiveObject<T>, key: keyof T, prev: any, next: any): void;
|
|
8
|
-
export declare function patchLiveObject<T extends Record<string, any>>(root: LiveObject<T>, prev: T, next: T): void;
|
|
9
|
-
export declare function patchImmutableObject<T>(state: T, updates: StorageUpdate[]): T;
|
package/lib/cjs/immutable.js
DELETED
|
@@ -1,291 +0,0 @@
|
|
|
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
|
-
let localI = i;
|
|
110
|
-
while (localI <= prevEnd) {
|
|
111
|
-
liveList.delete(i);
|
|
112
|
-
localI++;
|
|
113
|
-
}
|
|
114
|
-
}
|
|
115
|
-
else {
|
|
116
|
-
while (i <= prevEnd && i <= nextEnd) {
|
|
117
|
-
prevNode = prev[i];
|
|
118
|
-
nextNode = next[i];
|
|
119
|
-
const liveListNode = liveList.get(i);
|
|
120
|
-
if (liveListNode instanceof LiveObject_1.LiveObject &&
|
|
121
|
-
isPlainObject(prevNode) &&
|
|
122
|
-
isPlainObject(nextNode)) {
|
|
123
|
-
patchLiveObject(liveListNode, prevNode, nextNode);
|
|
124
|
-
}
|
|
125
|
-
else {
|
|
126
|
-
liveList.delete(i);
|
|
127
|
-
liveList.insert(anyToCrdt(nextNode), i);
|
|
128
|
-
}
|
|
129
|
-
i++;
|
|
130
|
-
}
|
|
131
|
-
while (i <= nextEnd) {
|
|
132
|
-
liveList.insert(anyToCrdt(next[i]), i);
|
|
133
|
-
i++;
|
|
134
|
-
}
|
|
135
|
-
while (i <= prevEnd) {
|
|
136
|
-
liveList.delete(i);
|
|
137
|
-
i++;
|
|
138
|
-
}
|
|
139
|
-
}
|
|
140
|
-
}
|
|
141
|
-
exports.patchLiveList = patchLiveList;
|
|
142
|
-
function patchLiveObjectKey(liveObject, key, prev, next) {
|
|
143
|
-
const value = liveObject.get(key);
|
|
144
|
-
if (next === undefined) {
|
|
145
|
-
liveObject.delete(key);
|
|
146
|
-
}
|
|
147
|
-
else if (value === undefined) {
|
|
148
|
-
liveObject.set(key, anyToCrdt(next));
|
|
149
|
-
}
|
|
150
|
-
else if (prev === next) {
|
|
151
|
-
return;
|
|
152
|
-
}
|
|
153
|
-
else if (value instanceof LiveList_1.LiveList &&
|
|
154
|
-
Array.isArray(prev) &&
|
|
155
|
-
Array.isArray(next)) {
|
|
156
|
-
patchLiveList(value, prev, next);
|
|
157
|
-
}
|
|
158
|
-
else if (value instanceof LiveObject_1.LiveObject &&
|
|
159
|
-
isPlainObject(prev) &&
|
|
160
|
-
isPlainObject(next)) {
|
|
161
|
-
patchLiveObject(value, prev, next);
|
|
162
|
-
}
|
|
163
|
-
else {
|
|
164
|
-
liveObject.set(key, anyToCrdt(next));
|
|
165
|
-
}
|
|
166
|
-
}
|
|
167
|
-
exports.patchLiveObjectKey = patchLiveObjectKey;
|
|
168
|
-
function patchLiveObject(root, prev, next) {
|
|
169
|
-
const updates = {};
|
|
170
|
-
for (const key in next) {
|
|
171
|
-
patchLiveObjectKey(root, key, prev[key], next[key]);
|
|
172
|
-
}
|
|
173
|
-
for (const key in prev) {
|
|
174
|
-
if (next[key] === undefined) {
|
|
175
|
-
root.delete(key);
|
|
176
|
-
}
|
|
177
|
-
}
|
|
178
|
-
if (Object.keys(updates).length > 0) {
|
|
179
|
-
root.update(updates);
|
|
180
|
-
}
|
|
181
|
-
}
|
|
182
|
-
exports.patchLiveObject = patchLiveObject;
|
|
183
|
-
function getParentsPath(node) {
|
|
184
|
-
const path = [];
|
|
185
|
-
while (node._parentKey != null && node._parent != null) {
|
|
186
|
-
if (node._parent instanceof LiveList_1.LiveList) {
|
|
187
|
-
path.push(node._parent._indexOfPosition(node._parentKey));
|
|
188
|
-
}
|
|
189
|
-
else {
|
|
190
|
-
path.push(node._parentKey);
|
|
191
|
-
}
|
|
192
|
-
node = node._parent;
|
|
193
|
-
}
|
|
194
|
-
return path;
|
|
195
|
-
}
|
|
196
|
-
function patchImmutableObject(state, updates) {
|
|
197
|
-
return updates.reduce((state, update) => patchImmutableObjectWithUpdate(state, update), state);
|
|
198
|
-
}
|
|
199
|
-
exports.patchImmutableObject = patchImmutableObject;
|
|
200
|
-
function patchImmutableObjectWithUpdate(state, update) {
|
|
201
|
-
const path = getParentsPath(update.node);
|
|
202
|
-
return patchImmutableNode(state, path, update);
|
|
203
|
-
}
|
|
204
|
-
function patchImmutableNode(state, path, update) {
|
|
205
|
-
var _a, _b, _c, _d;
|
|
206
|
-
const pathItem = path.pop();
|
|
207
|
-
if (pathItem === undefined) {
|
|
208
|
-
switch (update.type) {
|
|
209
|
-
case "LiveObject": {
|
|
210
|
-
if (typeof state !== "object") {
|
|
211
|
-
throw new Error("Internal: received update on LiveObject but state was not an object");
|
|
212
|
-
}
|
|
213
|
-
let newState = Object.assign({}, state);
|
|
214
|
-
for (const key in update.updates) {
|
|
215
|
-
if (((_a = update.updates[key]) === null || _a === void 0 ? void 0 : _a.type) === "update") {
|
|
216
|
-
newState[key] = liveNodeToJson(update.node.get(key));
|
|
217
|
-
}
|
|
218
|
-
else if (((_b = update.updates[key]) === null || _b === void 0 ? void 0 : _b.type) === "delete") {
|
|
219
|
-
delete newState[key];
|
|
220
|
-
}
|
|
221
|
-
}
|
|
222
|
-
return newState;
|
|
223
|
-
}
|
|
224
|
-
case "LiveList": {
|
|
225
|
-
if (Array.isArray(state) === false) {
|
|
226
|
-
throw new Error("Internal: received update on LiveList but state was not an array");
|
|
227
|
-
}
|
|
228
|
-
let newState = state.map((x) => x);
|
|
229
|
-
for (const listUpdate of update.updates) {
|
|
230
|
-
if (listUpdate.type === "insert") {
|
|
231
|
-
if (listUpdate.index === newState.length) {
|
|
232
|
-
newState.push(liveNodeToJson(listUpdate.item));
|
|
233
|
-
}
|
|
234
|
-
else {
|
|
235
|
-
newState = [
|
|
236
|
-
...newState.slice(0, listUpdate.index),
|
|
237
|
-
liveNodeToJson(listUpdate.item),
|
|
238
|
-
...newState.slice(listUpdate.index),
|
|
239
|
-
];
|
|
240
|
-
}
|
|
241
|
-
}
|
|
242
|
-
else if (listUpdate.type === "delete") {
|
|
243
|
-
newState.splice(listUpdate.index, 1);
|
|
244
|
-
}
|
|
245
|
-
else if (listUpdate.type === "move") {
|
|
246
|
-
if (listUpdate.previousIndex > listUpdate.index) {
|
|
247
|
-
newState = [
|
|
248
|
-
...newState.slice(0, listUpdate.index),
|
|
249
|
-
liveNodeToJson(listUpdate.item),
|
|
250
|
-
...newState.slice(listUpdate.index, listUpdate.previousIndex),
|
|
251
|
-
...newState.slice(listUpdate.previousIndex + 1),
|
|
252
|
-
];
|
|
253
|
-
}
|
|
254
|
-
else {
|
|
255
|
-
newState = [
|
|
256
|
-
...newState.slice(0, listUpdate.previousIndex),
|
|
257
|
-
...newState.slice(listUpdate.previousIndex + 1, listUpdate.index + 1),
|
|
258
|
-
liveNodeToJson(listUpdate.item),
|
|
259
|
-
...newState.slice(listUpdate.index + 1),
|
|
260
|
-
];
|
|
261
|
-
}
|
|
262
|
-
}
|
|
263
|
-
}
|
|
264
|
-
return newState;
|
|
265
|
-
}
|
|
266
|
-
case "LiveMap": {
|
|
267
|
-
if (typeof state !== "object") {
|
|
268
|
-
throw new Error("Internal: received update on LiveMap but state was not an object");
|
|
269
|
-
}
|
|
270
|
-
let newState = Object.assign({}, state);
|
|
271
|
-
for (const key in update.updates) {
|
|
272
|
-
if (((_c = update.updates[key]) === null || _c === void 0 ? void 0 : _c.type) === "update") {
|
|
273
|
-
newState[key] = liveNodeToJson(update.node.get(key));
|
|
274
|
-
}
|
|
275
|
-
else if (((_d = update.updates[key]) === null || _d === void 0 ? void 0 : _d.type) === "delete") {
|
|
276
|
-
delete newState[key];
|
|
277
|
-
}
|
|
278
|
-
}
|
|
279
|
-
return newState;
|
|
280
|
-
}
|
|
281
|
-
}
|
|
282
|
-
}
|
|
283
|
-
if (Array.isArray(state)) {
|
|
284
|
-
const newArray = [...state];
|
|
285
|
-
newArray[pathItem] = patchImmutableNode(state[pathItem], path, update);
|
|
286
|
-
return newArray;
|
|
287
|
-
}
|
|
288
|
-
else {
|
|
289
|
-
return Object.assign(Object.assign({}, state), { [pathItem]: patchImmutableNode(state[pathItem], path, update) });
|
|
290
|
-
}
|
|
291
|
-
}
|
|
@@ -1,66 +0,0 @@
|
|
|
1
|
-
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
|
|
2
|
-
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
|
|
3
|
-
return new (P || (P = Promise))(function (resolve, reject) {
|
|
4
|
-
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
|
|
5
|
-
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
|
|
6
|
-
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
|
|
7
|
-
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
|
8
|
-
});
|
|
9
|
-
};
|
|
10
|
-
function fetchAuthorize(endpoint, room, publicApiKey) {
|
|
11
|
-
return __awaiter(this, void 0, void 0, function* () {
|
|
12
|
-
const res = yield fetch(endpoint, {
|
|
13
|
-
method: "POST",
|
|
14
|
-
headers: {
|
|
15
|
-
"Content-Type": "application/json",
|
|
16
|
-
},
|
|
17
|
-
body: JSON.stringify({
|
|
18
|
-
room,
|
|
19
|
-
publicApiKey,
|
|
20
|
-
}),
|
|
21
|
-
});
|
|
22
|
-
if (!res.ok) {
|
|
23
|
-
throw new AuthenticationError(`Authentication error. Liveblocks could not parse the response of your authentication "${endpoint}"`);
|
|
24
|
-
}
|
|
25
|
-
let authResponse = null;
|
|
26
|
-
try {
|
|
27
|
-
authResponse = yield res.json();
|
|
28
|
-
}
|
|
29
|
-
catch (er) {
|
|
30
|
-
throw new AuthenticationError(`Authentication error. Liveblocks could not parse the response of your authentication "${endpoint}"`);
|
|
31
|
-
}
|
|
32
|
-
if (typeof authResponse.token !== "string") {
|
|
33
|
-
throw new AuthenticationError(`Authentication error. Liveblocks could not parse the response of your authentication "${endpoint}"`);
|
|
34
|
-
}
|
|
35
|
-
return authResponse.token;
|
|
36
|
-
});
|
|
37
|
-
}
|
|
38
|
-
export default function auth(endpoint, room, publicApiKey) {
|
|
39
|
-
return __awaiter(this, void 0, void 0, function* () {
|
|
40
|
-
if (typeof endpoint === "string") {
|
|
41
|
-
return fetchAuthorize(endpoint, room, publicApiKey);
|
|
42
|
-
}
|
|
43
|
-
if (typeof endpoint === "function") {
|
|
44
|
-
const { token } = yield endpoint(room);
|
|
45
|
-
// TODO: Validation
|
|
46
|
-
return token;
|
|
47
|
-
}
|
|
48
|
-
throw new Error("Authentication error. Liveblocks could not parse the response of your authentication endpoint");
|
|
49
|
-
});
|
|
50
|
-
}
|
|
51
|
-
class AuthenticationError extends Error {
|
|
52
|
-
constructor(message) {
|
|
53
|
-
super(message);
|
|
54
|
-
}
|
|
55
|
-
}
|
|
56
|
-
export function parseToken(token) {
|
|
57
|
-
const tokenParts = token.split(".");
|
|
58
|
-
if (tokenParts.length !== 3) {
|
|
59
|
-
throw new AuthenticationError(`Authentication error. Liveblocks could not parse the response of your authentication endpoint`);
|
|
60
|
-
}
|
|
61
|
-
const data = JSON.parse(atob(tokenParts[1]));
|
|
62
|
-
if (typeof data.actor !== "number") {
|
|
63
|
-
throw new AuthenticationError(`Authentication error. Liveblocks could not parse the response of your authentication endpoint`);
|
|
64
|
-
}
|
|
65
|
-
return data;
|
|
66
|
-
}
|
package/lib/esm/immutable.d.ts
DELETED
|
@@ -1,9 +0,0 @@
|
|
|
1
|
-
import { LiveList } from "./LiveList";
|
|
2
|
-
import { LiveObject } from "./LiveObject";
|
|
3
|
-
import { StorageUpdate } from "./types";
|
|
4
|
-
export declare function liveObjectToJson(liveObject: LiveObject<any>): any;
|
|
5
|
-
export declare function liveNodeToJson(value: any): any;
|
|
6
|
-
export declare function patchLiveList<T>(liveList: LiveList<T>, prev: Array<T>, next: Array<T>): void;
|
|
7
|
-
export declare function patchLiveObjectKey<T>(liveObject: LiveObject<T>, key: keyof T, prev: any, next: any): void;
|
|
8
|
-
export declare function patchLiveObject<T extends Record<string, any>>(root: LiveObject<T>, prev: T, next: T): void;
|
|
9
|
-
export declare function patchImmutableObject<T>(state: T, updates: StorageUpdate[]): T;
|
package/lib/esm/immutable.js
DELETED
|
@@ -1,282 +0,0 @@
|
|
|
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
|
-
let localI = i;
|
|
105
|
-
while (localI <= prevEnd) {
|
|
106
|
-
liveList.delete(i);
|
|
107
|
-
localI++;
|
|
108
|
-
}
|
|
109
|
-
}
|
|
110
|
-
else {
|
|
111
|
-
while (i <= prevEnd && i <= nextEnd) {
|
|
112
|
-
prevNode = prev[i];
|
|
113
|
-
nextNode = next[i];
|
|
114
|
-
const liveListNode = liveList.get(i);
|
|
115
|
-
if (liveListNode instanceof LiveObject &&
|
|
116
|
-
isPlainObject(prevNode) &&
|
|
117
|
-
isPlainObject(nextNode)) {
|
|
118
|
-
patchLiveObject(liveListNode, prevNode, nextNode);
|
|
119
|
-
}
|
|
120
|
-
else {
|
|
121
|
-
liveList.delete(i);
|
|
122
|
-
liveList.insert(anyToCrdt(nextNode), i);
|
|
123
|
-
}
|
|
124
|
-
i++;
|
|
125
|
-
}
|
|
126
|
-
while (i <= nextEnd) {
|
|
127
|
-
liveList.insert(anyToCrdt(next[i]), i);
|
|
128
|
-
i++;
|
|
129
|
-
}
|
|
130
|
-
while (i <= prevEnd) {
|
|
131
|
-
liveList.delete(i);
|
|
132
|
-
i++;
|
|
133
|
-
}
|
|
134
|
-
}
|
|
135
|
-
}
|
|
136
|
-
export function patchLiveObjectKey(liveObject, key, prev, next) {
|
|
137
|
-
const value = liveObject.get(key);
|
|
138
|
-
if (next === undefined) {
|
|
139
|
-
liveObject.delete(key);
|
|
140
|
-
}
|
|
141
|
-
else if (value === undefined) {
|
|
142
|
-
liveObject.set(key, anyToCrdt(next));
|
|
143
|
-
}
|
|
144
|
-
else if (prev === next) {
|
|
145
|
-
return;
|
|
146
|
-
}
|
|
147
|
-
else if (value instanceof LiveList &&
|
|
148
|
-
Array.isArray(prev) &&
|
|
149
|
-
Array.isArray(next)) {
|
|
150
|
-
patchLiveList(value, prev, next);
|
|
151
|
-
}
|
|
152
|
-
else if (value instanceof LiveObject &&
|
|
153
|
-
isPlainObject(prev) &&
|
|
154
|
-
isPlainObject(next)) {
|
|
155
|
-
patchLiveObject(value, prev, next);
|
|
156
|
-
}
|
|
157
|
-
else {
|
|
158
|
-
liveObject.set(key, anyToCrdt(next));
|
|
159
|
-
}
|
|
160
|
-
}
|
|
161
|
-
export function patchLiveObject(root, prev, next) {
|
|
162
|
-
const updates = {};
|
|
163
|
-
for (const key in next) {
|
|
164
|
-
patchLiveObjectKey(root, key, prev[key], next[key]);
|
|
165
|
-
}
|
|
166
|
-
for (const key in prev) {
|
|
167
|
-
if (next[key] === undefined) {
|
|
168
|
-
root.delete(key);
|
|
169
|
-
}
|
|
170
|
-
}
|
|
171
|
-
if (Object.keys(updates).length > 0) {
|
|
172
|
-
root.update(updates);
|
|
173
|
-
}
|
|
174
|
-
}
|
|
175
|
-
function getParentsPath(node) {
|
|
176
|
-
const path = [];
|
|
177
|
-
while (node._parentKey != null && node._parent != null) {
|
|
178
|
-
if (node._parent instanceof LiveList) {
|
|
179
|
-
path.push(node._parent._indexOfPosition(node._parentKey));
|
|
180
|
-
}
|
|
181
|
-
else {
|
|
182
|
-
path.push(node._parentKey);
|
|
183
|
-
}
|
|
184
|
-
node = node._parent;
|
|
185
|
-
}
|
|
186
|
-
return path;
|
|
187
|
-
}
|
|
188
|
-
export function patchImmutableObject(state, updates) {
|
|
189
|
-
return updates.reduce((state, update) => patchImmutableObjectWithUpdate(state, update), state);
|
|
190
|
-
}
|
|
191
|
-
function patchImmutableObjectWithUpdate(state, update) {
|
|
192
|
-
const path = getParentsPath(update.node);
|
|
193
|
-
return patchImmutableNode(state, path, update);
|
|
194
|
-
}
|
|
195
|
-
function patchImmutableNode(state, path, update) {
|
|
196
|
-
var _a, _b, _c, _d;
|
|
197
|
-
const pathItem = path.pop();
|
|
198
|
-
if (pathItem === undefined) {
|
|
199
|
-
switch (update.type) {
|
|
200
|
-
case "LiveObject": {
|
|
201
|
-
if (typeof state !== "object") {
|
|
202
|
-
throw new Error("Internal: received update on LiveObject but state was not an object");
|
|
203
|
-
}
|
|
204
|
-
let newState = Object.assign({}, state);
|
|
205
|
-
for (const key in update.updates) {
|
|
206
|
-
if (((_a = update.updates[key]) === null || _a === void 0 ? void 0 : _a.type) === "update") {
|
|
207
|
-
newState[key] = liveNodeToJson(update.node.get(key));
|
|
208
|
-
}
|
|
209
|
-
else if (((_b = update.updates[key]) === null || _b === void 0 ? void 0 : _b.type) === "delete") {
|
|
210
|
-
delete newState[key];
|
|
211
|
-
}
|
|
212
|
-
}
|
|
213
|
-
return newState;
|
|
214
|
-
}
|
|
215
|
-
case "LiveList": {
|
|
216
|
-
if (Array.isArray(state) === false) {
|
|
217
|
-
throw new Error("Internal: received update on LiveList but state was not an array");
|
|
218
|
-
}
|
|
219
|
-
let newState = state.map((x) => x);
|
|
220
|
-
for (const listUpdate of update.updates) {
|
|
221
|
-
if (listUpdate.type === "insert") {
|
|
222
|
-
if (listUpdate.index === newState.length) {
|
|
223
|
-
newState.push(liveNodeToJson(listUpdate.item));
|
|
224
|
-
}
|
|
225
|
-
else {
|
|
226
|
-
newState = [
|
|
227
|
-
...newState.slice(0, listUpdate.index),
|
|
228
|
-
liveNodeToJson(listUpdate.item),
|
|
229
|
-
...newState.slice(listUpdate.index),
|
|
230
|
-
];
|
|
231
|
-
}
|
|
232
|
-
}
|
|
233
|
-
else if (listUpdate.type === "delete") {
|
|
234
|
-
newState.splice(listUpdate.index, 1);
|
|
235
|
-
}
|
|
236
|
-
else if (listUpdate.type === "move") {
|
|
237
|
-
if (listUpdate.previousIndex > listUpdate.index) {
|
|
238
|
-
newState = [
|
|
239
|
-
...newState.slice(0, listUpdate.index),
|
|
240
|
-
liveNodeToJson(listUpdate.item),
|
|
241
|
-
...newState.slice(listUpdate.index, listUpdate.previousIndex),
|
|
242
|
-
...newState.slice(listUpdate.previousIndex + 1),
|
|
243
|
-
];
|
|
244
|
-
}
|
|
245
|
-
else {
|
|
246
|
-
newState = [
|
|
247
|
-
...newState.slice(0, listUpdate.previousIndex),
|
|
248
|
-
...newState.slice(listUpdate.previousIndex + 1, listUpdate.index + 1),
|
|
249
|
-
liveNodeToJson(listUpdate.item),
|
|
250
|
-
...newState.slice(listUpdate.index + 1),
|
|
251
|
-
];
|
|
252
|
-
}
|
|
253
|
-
}
|
|
254
|
-
}
|
|
255
|
-
return newState;
|
|
256
|
-
}
|
|
257
|
-
case "LiveMap": {
|
|
258
|
-
if (typeof state !== "object") {
|
|
259
|
-
throw new Error("Internal: received update on LiveMap but state was not an object");
|
|
260
|
-
}
|
|
261
|
-
let newState = Object.assign({}, state);
|
|
262
|
-
for (const key in update.updates) {
|
|
263
|
-
if (((_c = update.updates[key]) === null || _c === void 0 ? void 0 : _c.type) === "update") {
|
|
264
|
-
newState[key] = liveNodeToJson(update.node.get(key));
|
|
265
|
-
}
|
|
266
|
-
else if (((_d = update.updates[key]) === null || _d === void 0 ? void 0 : _d.type) === "delete") {
|
|
267
|
-
delete newState[key];
|
|
268
|
-
}
|
|
269
|
-
}
|
|
270
|
-
return newState;
|
|
271
|
-
}
|
|
272
|
-
}
|
|
273
|
-
}
|
|
274
|
-
if (Array.isArray(state)) {
|
|
275
|
-
const newArray = [...state];
|
|
276
|
-
newArray[pathItem] = patchImmutableNode(state[pathItem], path, update);
|
|
277
|
-
return newArray;
|
|
278
|
-
}
|
|
279
|
-
else {
|
|
280
|
-
return Object.assign(Object.assign({}, state), { [pathItem]: patchImmutableNode(state[pathItem], path, update) });
|
|
281
|
-
}
|
|
282
|
-
}
|