@liveblocks/client 0.16.4-beta1 → 0.16.5
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/index.js +826 -1893
- package/index.mjs +779 -1613
- package/internal.d.ts +29 -44
- package/internal.js +171 -31
- package/internal.mjs +148 -1
- package/package.json +20 -7
- package/shared.d.ts +39 -9
- package/shared.js +1275 -2386
- package/shared.mjs +1183 -1887
package/internal.d.ts
CHANGED
|
@@ -1,10 +1,10 @@
|
|
|
1
|
-
import { J as Json,
|
|
2
|
-
export { g as Resolve } from './shared';
|
|
1
|
+
import { d as JsonObject, J as Json, e as Lson, A as AbstractCrdt, f as LsonObject, L as LiveObject, S as StorageUpdate } from './shared';
|
|
2
|
+
export { g as Resolve, h as RoomInitializers } from './shared';
|
|
3
3
|
|
|
4
4
|
/**
|
|
5
5
|
* Messages that can be sent from the server to the client.
|
|
6
6
|
*/
|
|
7
|
-
declare type ServerMessage = UpdatePresenceMessage | UserJoinMessage | UserLeftMessage | EventMessage | RoomStateMessage | InitialDocumentStateMessage | UpdateStorageMessage;
|
|
7
|
+
declare type ServerMessage<TPresence extends JsonObject> = UpdatePresenceMessage<TPresence> | UserJoinMessage | UserLeftMessage | EventMessage | RoomStateMessage | InitialDocumentStateMessage | UpdateStorageMessage;
|
|
8
8
|
declare enum ServerMessageType {
|
|
9
9
|
UpdatePresence = 100,
|
|
10
10
|
UserJoined = 101,
|
|
@@ -39,7 +39,7 @@ declare type RoomStateMessage = {
|
|
|
39
39
|
* those cases, the `targetActor` field indicates the newly connected client,
|
|
40
40
|
* so all other existing clients can ignore this broadcasted message.
|
|
41
41
|
*/
|
|
42
|
-
declare type UpdatePresenceMessage = {
|
|
42
|
+
declare type UpdatePresenceMessage<TPresence extends JsonObject> = {
|
|
43
43
|
type: ServerMessageType.UpdatePresence;
|
|
44
44
|
/**
|
|
45
45
|
* The User whose Presence has changed.
|
|
@@ -50,7 +50,7 @@ declare type UpdatePresenceMessage = {
|
|
|
50
50
|
* this will be the full Presence, otherwise it only contain the fields that
|
|
51
51
|
* have changed since the last broadcast.
|
|
52
52
|
*/
|
|
53
|
-
data:
|
|
53
|
+
data: TPresence;
|
|
54
54
|
/**
|
|
55
55
|
* If this message was sent in response to a newly joined user, this field
|
|
56
56
|
* indicates which client this message is for. Other existing clients may
|
|
@@ -121,32 +121,12 @@ declare type UpdateStorageMessage = {
|
|
|
121
121
|
type: ServerMessageType.UpdateStorage;
|
|
122
122
|
ops: Op[];
|
|
123
123
|
};
|
|
124
|
-
/**
|
|
125
|
-
* Messages that can be sent from the client to the server.
|
|
126
|
-
*/
|
|
127
|
-
declare type ClientMessage = ClientEventMessage | UpdatePresenceClientMessage | UpdateStorageClientMessage | FetchStorageClientMessage;
|
|
128
124
|
declare enum ClientMessageType {
|
|
129
125
|
UpdatePresence = 100,
|
|
130
126
|
ClientEvent = 103,
|
|
131
127
|
FetchStorage = 200,
|
|
132
128
|
UpdateStorage = 201
|
|
133
129
|
}
|
|
134
|
-
declare type ClientEventMessage = {
|
|
135
|
-
type: ClientMessageType.ClientEvent;
|
|
136
|
-
event: Json;
|
|
137
|
-
};
|
|
138
|
-
declare type UpdatePresenceClientMessage = {
|
|
139
|
-
type: ClientMessageType.UpdatePresence;
|
|
140
|
-
data: Presence;
|
|
141
|
-
targetActor?: number;
|
|
142
|
-
};
|
|
143
|
-
declare type UpdateStorageClientMessage = {
|
|
144
|
-
type: ClientMessageType.UpdateStorage;
|
|
145
|
-
ops: Op[];
|
|
146
|
-
};
|
|
147
|
-
declare type FetchStorageClientMessage = {
|
|
148
|
-
type: ClientMessageType.FetchStorage;
|
|
149
|
-
};
|
|
150
130
|
declare enum CrdtType {
|
|
151
131
|
Object = 0,
|
|
152
132
|
List = 1,
|
|
@@ -192,7 +172,6 @@ declare enum OpType {
|
|
|
192
172
|
* only.
|
|
193
173
|
*/
|
|
194
174
|
declare type Op = CreateObjectOp | UpdateObjectOp | DeleteCrdtOp | CreateListOp | SetParentKeyOp | DeleteObjectKeyOp | CreateMapOp | CreateRegisterOp;
|
|
195
|
-
declare type CreateOp = CreateObjectOp | CreateRegisterOp | CreateMapOp | CreateListOp;
|
|
196
175
|
declare type UpdateObjectOp = {
|
|
197
176
|
opId?: string;
|
|
198
177
|
id: string;
|
|
@@ -250,24 +229,12 @@ declare type DeleteObjectKeyOp = {
|
|
|
250
229
|
type: OpType.DeleteObjectKey;
|
|
251
230
|
key: string;
|
|
252
231
|
};
|
|
253
|
-
declare enum WebsocketCloseCodes {
|
|
254
|
-
CLOSE_ABNORMAL = 1006,
|
|
255
|
-
INVALID_MESSAGE_FORMAT = 4000,
|
|
256
|
-
NOT_ALLOWED = 4001,
|
|
257
|
-
MAX_NUMBER_OF_MESSAGES_PER_SECONDS = 4002,
|
|
258
|
-
MAX_NUMBER_OF_CONCURRENT_CONNECTIONS = 4003,
|
|
259
|
-
MAX_NUMBER_OF_MESSAGES_PER_DAY_PER_APP = 4004,
|
|
260
|
-
MAX_NUMBER_OF_CONCURRENT_CONNECTIONS_PER_ROOM = 4005,
|
|
261
|
-
CLOSE_WITHOUT_RETRY = 4999
|
|
262
|
-
}
|
|
263
|
-
|
|
264
|
-
declare const min = 32;
|
|
265
|
-
declare const max = 126;
|
|
266
|
-
declare function makePosition(before?: string, after?: string): string;
|
|
267
|
-
declare function posCodes(str: string): number[];
|
|
268
|
-
declare function pos(codes: number[]): string;
|
|
269
|
-
declare function compare(posA: string, posB: string): number;
|
|
270
232
|
|
|
233
|
+
/**
|
|
234
|
+
* Tools to help with the controlled deprecation of public APIs.
|
|
235
|
+
*
|
|
236
|
+
* First warn, then error, then remove eventually.
|
|
237
|
+
*/
|
|
271
238
|
/**
|
|
272
239
|
* Displays a deprecation warning in the dev console. Only in dev mode, and
|
|
273
240
|
* only once per message/key. In production, this is a no-op.
|
|
@@ -279,5 +246,23 @@ declare function deprecate(message: string, key?: string): void;
|
|
|
279
246
|
* only once per message/key. In production, this is a no-op.
|
|
280
247
|
*/
|
|
281
248
|
declare function deprecateIf(condition: unknown, message: string, key?: string): void;
|
|
249
|
+
/**
|
|
250
|
+
* Throws a deprecation error in the dev console.
|
|
251
|
+
*
|
|
252
|
+
* Only triggers in dev mode. In production, this is a no-op.
|
|
253
|
+
*/
|
|
254
|
+
declare function throwUsageError(message: string): void;
|
|
255
|
+
/**
|
|
256
|
+
* Conditionally throws a usage error in the dev console if the first argument
|
|
257
|
+
* is truthy. Use this to "escalate" usage patterns that in previous versions
|
|
258
|
+
* we already warned about with deprecation warnings.
|
|
259
|
+
*
|
|
260
|
+
* Only has effect in dev mode. In production, this is a no-op.
|
|
261
|
+
*/
|
|
262
|
+
declare function errorIf(condition: unknown, message: string): void;
|
|
263
|
+
|
|
264
|
+
declare function lsonToJson(value: Lson | AbstractCrdt): Json;
|
|
265
|
+
declare function patchLiveObjectKey<O extends LsonObject>(liveObject: LiveObject<O>, key: keyof O, prev: unknown, next: unknown): void;
|
|
266
|
+
declare function patchImmutableObject<T>(state: T, updates: StorageUpdate[]): T;
|
|
282
267
|
|
|
283
|
-
export {
|
|
268
|
+
export { ClientMessageType, CrdtType, OpType, RoomStateMessage, SerializedCrdtWithId, ServerMessage, ServerMessageType, deprecate, deprecateIf, errorIf, lsonToJson, patchImmutableObject, patchLiveObjectKey, throwUsageError };
|
package/internal.js
CHANGED
|
@@ -1,36 +1,176 @@
|
|
|
1
|
-
|
|
1
|
+
"use strict";
|
|
2
2
|
|
|
3
|
-
Object.defineProperty(exports,
|
|
3
|
+
Object.defineProperty(exports, "__esModule", {
|
|
4
|
+
value: !0
|
|
5
|
+
});
|
|
4
6
|
|
|
5
|
-
var LiveObject = require(
|
|
7
|
+
var LiveObject = require("./shared.js");
|
|
6
8
|
|
|
9
|
+
function lsonObjectToJson(obj) {
|
|
10
|
+
var result = {};
|
|
11
|
+
for (var _key in obj) {
|
|
12
|
+
var val = obj[_key];
|
|
13
|
+
void 0 !== val && (result[_key] = lsonToJson(val));
|
|
14
|
+
}
|
|
15
|
+
return result;
|
|
16
|
+
}
|
|
7
17
|
|
|
18
|
+
function lsonListToJson(value) {
|
|
19
|
+
return value.map(lsonToJson);
|
|
20
|
+
}
|
|
8
21
|
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
});
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
}
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
}
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
22
|
+
function lsonToJson(value) {
|
|
23
|
+
if (value instanceof LiveObject.LiveObject) return lsonObjectToJson(value.toObject());
|
|
24
|
+
if (value instanceof LiveObject.LiveList) return function(value) {
|
|
25
|
+
return lsonListToJson(value.toArray());
|
|
26
|
+
}(value);
|
|
27
|
+
if (value instanceof LiveObject.LiveMap) return function(map) {
|
|
28
|
+
for (var _step, result = {}, _iterator = LiveObject._createForOfIteratorHelperLoose(map.entries()); !(_step = _iterator()).done; ) {
|
|
29
|
+
var _step$value = _step.value, _key2 = _step$value[0], value = _step$value[1];
|
|
30
|
+
result[_key2] = lsonToJson(value);
|
|
31
|
+
}
|
|
32
|
+
return result;
|
|
33
|
+
}(value);
|
|
34
|
+
if (value instanceof LiveObject.LiveRegister) return value.data;
|
|
35
|
+
if (value instanceof LiveObject.AbstractCrdt) throw new Error("Unhandled subclass of AbstractCrdt encountered");
|
|
36
|
+
return Array.isArray(value) ? lsonListToJson(value) : isPlainObject(value) ? lsonObjectToJson(value) : value;
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
function isPlainObject(obj) {
|
|
40
|
+
return null !== obj && "[object Object]" === Object.prototype.toString.call(obj);
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
function anyToCrdt(obj) {
|
|
44
|
+
if (null == obj) return obj;
|
|
45
|
+
if (Array.isArray(obj)) return new LiveObject.LiveList(obj.map(anyToCrdt));
|
|
46
|
+
if (isPlainObject(obj)) {
|
|
47
|
+
var init = {};
|
|
48
|
+
for (var _key3 in obj) init[_key3] = anyToCrdt(obj[_key3]);
|
|
49
|
+
return new LiveObject.LiveObject(init);
|
|
50
|
+
}
|
|
51
|
+
return obj;
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
function patchLiveObjectKey(liveObject, key, prev, next) {
|
|
55
|
+
if ("production" !== process.env.NODE_ENV) {
|
|
56
|
+
var nonSerializableValue = LiveObject.findNonSerializableValue(next);
|
|
57
|
+
if (nonSerializableValue) return void console.error("New state path: '" + nonSerializableValue.path + "' value: '" + nonSerializableValue.value + "' is not serializable.\nOnly serializable value can be synced with Liveblocks.");
|
|
58
|
+
}
|
|
59
|
+
var value = liveObject.get(key);
|
|
60
|
+
if (void 0 === next) liveObject.delete(key); else if (void 0 === value) liveObject.set(key, anyToCrdt(next)); else {
|
|
61
|
+
if (prev === next) return;
|
|
62
|
+
value instanceof LiveObject.LiveList && Array.isArray(prev) && Array.isArray(next) ? function(liveList, prev, next) {
|
|
63
|
+
var i = 0, prevEnd = prev.length - 1, nextEnd = next.length - 1, prevNode = prev[0], nextNode = next[0];
|
|
64
|
+
outer: {
|
|
65
|
+
for (;prevNode === nextNode; ) {
|
|
66
|
+
if (++i > prevEnd || i > nextEnd) break outer;
|
|
67
|
+
prevNode = prev[i], nextNode = next[i];
|
|
68
|
+
}
|
|
69
|
+
for (prevNode = prev[prevEnd], nextNode = next[nextEnd]; prevNode === nextNode; ) {
|
|
70
|
+
if (nextEnd--, i > --prevEnd || i > nextEnd) break outer;
|
|
71
|
+
prevNode = prev[prevEnd], nextNode = next[nextEnd];
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
if (i > prevEnd) {
|
|
75
|
+
if (i <= nextEnd) for (;i <= nextEnd; ) liveList.insert(anyToCrdt(next[i]), i),
|
|
76
|
+
i++;
|
|
77
|
+
} else if (i > nextEnd) for (var localI = i; localI <= prevEnd; ) liveList.delete(i),
|
|
78
|
+
localI++; else {
|
|
79
|
+
for (;i <= prevEnd && i <= nextEnd; ) {
|
|
80
|
+
prevNode = prev[i], nextNode = next[i];
|
|
81
|
+
var liveListNode = liveList.get(i);
|
|
82
|
+
liveListNode instanceof LiveObject.LiveObject && isPlainObject(prevNode) && isPlainObject(nextNode) ? patchLiveObject(liveListNode, prevNode, nextNode) : liveList.set(i, anyToCrdt(nextNode)),
|
|
83
|
+
i++;
|
|
84
|
+
}
|
|
85
|
+
for (;i <= nextEnd; ) liveList.insert(anyToCrdt(next[i]), i), i++;
|
|
86
|
+
for (var _localI = i; _localI <= prevEnd; ) liveList.delete(i), _localI++;
|
|
87
|
+
}
|
|
88
|
+
}(value, prev, next) : value instanceof LiveObject.LiveObject && isPlainObject(prev) && isPlainObject(next) ? patchLiveObject(value, prev, next) : liveObject.set(key, anyToCrdt(next));
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
function patchLiveObject(root, prev, next) {
|
|
93
|
+
var updates = {};
|
|
94
|
+
for (var _key4 in next) patchLiveObjectKey(root, _key4, prev[_key4], next[_key4]);
|
|
95
|
+
for (var _key5 in prev) void 0 === next[_key5] && root.delete(_key5);
|
|
96
|
+
Object.keys(updates).length > 0 && root.update(updates);
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
function patchImmutableNode(state, path, update) {
|
|
100
|
+
var _extends2, pathItem = path.pop();
|
|
101
|
+
if (void 0 === pathItem) switch (update.type) {
|
|
102
|
+
case "LiveObject":
|
|
103
|
+
if ("object" != typeof state) throw new Error("Internal: received update on LiveObject but state was not an object");
|
|
104
|
+
var newState = Object.assign({}, state);
|
|
105
|
+
for (var _key6 in update.updates) {
|
|
106
|
+
var _update$updates$_key, _update$updates$_key2;
|
|
107
|
+
if ("update" === (null == (_update$updates$_key = update.updates[_key6]) ? void 0 : _update$updates$_key.type)) {
|
|
108
|
+
var val = update.node.get(_key6);
|
|
109
|
+
void 0 !== val && (newState[_key6] = lsonToJson(val));
|
|
110
|
+
} else "delete" === (null == (_update$updates$_key2 = update.updates[_key6]) ? void 0 : _update$updates$_key2.type) && delete newState[_key6];
|
|
111
|
+
}
|
|
112
|
+
return newState;
|
|
113
|
+
|
|
114
|
+
case "LiveList":
|
|
115
|
+
if (!1 === Array.isArray(state)) throw new Error("Internal: received update on LiveList but state was not an array");
|
|
116
|
+
for (var _step2, _newState = state.map((function(x) {
|
|
117
|
+
return x;
|
|
118
|
+
})), _loop = function() {
|
|
119
|
+
var listUpdate = _step2.value;
|
|
120
|
+
"set" === listUpdate.type ? _newState = _newState.map((function(item, index) {
|
|
121
|
+
return index === listUpdate.index ? listUpdate.item : item;
|
|
122
|
+
})) : "insert" === listUpdate.type ? listUpdate.index === _newState.length ? _newState.push(lsonToJson(listUpdate.item)) : _newState = [].concat(_newState.slice(0, listUpdate.index), [ lsonToJson(listUpdate.item) ], _newState.slice(listUpdate.index)) : "delete" === listUpdate.type ? _newState.splice(listUpdate.index, 1) : "move" === listUpdate.type && (_newState = listUpdate.previousIndex > listUpdate.index ? [].concat(_newState.slice(0, listUpdate.index), [ lsonToJson(listUpdate.item) ], _newState.slice(listUpdate.index, listUpdate.previousIndex), _newState.slice(listUpdate.previousIndex + 1)) : [].concat(_newState.slice(0, listUpdate.previousIndex), _newState.slice(listUpdate.previousIndex + 1, listUpdate.index + 1), [ lsonToJson(listUpdate.item) ], _newState.slice(listUpdate.index + 1)));
|
|
123
|
+
}, _iterator2 = LiveObject._createForOfIteratorHelperLoose(update.updates); !(_step2 = _iterator2()).done; ) _loop();
|
|
124
|
+
return _newState;
|
|
125
|
+
|
|
126
|
+
case "LiveMap":
|
|
127
|
+
if ("object" != typeof state) throw new Error("Internal: received update on LiveMap but state was not an object");
|
|
128
|
+
var _newState2 = Object.assign({}, state);
|
|
129
|
+
for (var _key7 in update.updates) {
|
|
130
|
+
var _update$updates$_key3, _update$updates$_key4;
|
|
131
|
+
"update" === (null == (_update$updates$_key3 = update.updates[_key7]) ? void 0 : _update$updates$_key3.type) ? _newState2[_key7] = lsonToJson(update.node.get(_key7)) : "delete" === (null == (_update$updates$_key4 = update.updates[_key7]) ? void 0 : _update$updates$_key4.type) && delete _newState2[_key7];
|
|
132
|
+
}
|
|
133
|
+
return _newState2;
|
|
134
|
+
}
|
|
135
|
+
if (Array.isArray(state)) {
|
|
136
|
+
var newArray = [].concat(state);
|
|
137
|
+
return newArray[pathItem] = patchImmutableNode(state[pathItem], path, update), newArray;
|
|
138
|
+
}
|
|
139
|
+
return LiveObject._extends({}, state, ((_extends2 = {})[pathItem] = patchImmutableNode(state[pathItem], path, update),
|
|
140
|
+
_extends2));
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
Object.defineProperty(exports, "ClientMessageType", {
|
|
144
|
+
enumerable: !0,
|
|
145
|
+
get: function() {
|
|
146
|
+
return LiveObject.ClientMessageType;
|
|
147
|
+
}
|
|
148
|
+
}), Object.defineProperty(exports, "CrdtType", {
|
|
149
|
+
enumerable: !0,
|
|
150
|
+
get: function() {
|
|
151
|
+
return LiveObject.CrdtType;
|
|
152
|
+
}
|
|
153
|
+
}), Object.defineProperty(exports, "OpType", {
|
|
154
|
+
enumerable: !0,
|
|
155
|
+
get: function() {
|
|
156
|
+
return LiveObject.OpType;
|
|
157
|
+
}
|
|
158
|
+
}), Object.defineProperty(exports, "ServerMessageType", {
|
|
159
|
+
enumerable: !0,
|
|
160
|
+
get: function() {
|
|
161
|
+
return LiveObject.ServerMessageType;
|
|
162
|
+
}
|
|
163
|
+
}), exports.deprecate = LiveObject.deprecate, exports.deprecateIf = LiveObject.deprecateIf,
|
|
164
|
+
exports.errorIf = LiveObject.errorIf, exports.throwUsageError = LiveObject.throwUsageError,
|
|
165
|
+
exports.lsonToJson = lsonToJson, exports.patchImmutableObject = function(state, updates) {
|
|
166
|
+
return updates.reduce((function(state, update) {
|
|
167
|
+
return function(state, update) {
|
|
168
|
+
var path = function(node) {
|
|
169
|
+
for (var path = []; null != node._parentKey && null != node._parent; ) node._parent instanceof LiveObject.LiveList ? path.push(node._parent._indexOfPosition(node._parentKey)) : path.push(node._parentKey),
|
|
170
|
+
node = node._parent;
|
|
171
|
+
return path;
|
|
172
|
+
}(update.node);
|
|
173
|
+
return patchImmutableNode(state, path, update);
|
|
174
|
+
}(state, update);
|
|
175
|
+
}), state);
|
|
176
|
+
}, exports.patchLiveObjectKey = patchLiveObjectKey;
|
package/internal.mjs
CHANGED
|
@@ -1 +1,148 @@
|
|
|
1
|
-
|
|
1
|
+
import { L as LiveObject, b as LiveList, h as LiveMap, j as LiveRegister, A as AbstractCrdt, k as findNonSerializableValue } from "./shared.mjs";
|
|
2
|
+
|
|
3
|
+
export { C as ClientMessageType, l as CrdtType, O as OpType, S as ServerMessageType, n as deprecate, f as deprecateIf, o as errorIf, t as throwUsageError } from "./shared.mjs";
|
|
4
|
+
|
|
5
|
+
function lsonObjectToJson(obj) {
|
|
6
|
+
const result = {};
|
|
7
|
+
for (const key in obj) {
|
|
8
|
+
const val = obj[key];
|
|
9
|
+
void 0 !== val && (result[key] = lsonToJson(val));
|
|
10
|
+
}
|
|
11
|
+
return result;
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
function lsonListToJson(value) {
|
|
15
|
+
return value.map(lsonToJson);
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
function lsonToJson(value) {
|
|
19
|
+
if (value instanceof LiveObject) return lsonObjectToJson(value.toObject());
|
|
20
|
+
if (value instanceof LiveList) return function(value) {
|
|
21
|
+
return lsonListToJson(value.toArray());
|
|
22
|
+
}(value);
|
|
23
|
+
if (value instanceof LiveMap) return function(map) {
|
|
24
|
+
const result = {};
|
|
25
|
+
for (const [key, value] of map.entries()) result[key] = lsonToJson(value);
|
|
26
|
+
return result;
|
|
27
|
+
}(value);
|
|
28
|
+
if (value instanceof LiveRegister) return value.data;
|
|
29
|
+
if (value instanceof AbstractCrdt) throw new Error("Unhandled subclass of AbstractCrdt encountered");
|
|
30
|
+
return Array.isArray(value) ? lsonListToJson(value) : isPlainObject(value) ? lsonObjectToJson(value) : value;
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
function isPlainObject(obj) {
|
|
34
|
+
return null !== obj && "[object Object]" === Object.prototype.toString.call(obj);
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
function anyToCrdt(obj) {
|
|
38
|
+
if (null == obj) return obj;
|
|
39
|
+
if (Array.isArray(obj)) return new LiveList(obj.map(anyToCrdt));
|
|
40
|
+
if (isPlainObject(obj)) {
|
|
41
|
+
const init = {};
|
|
42
|
+
for (const key in obj) init[key] = anyToCrdt(obj[key]);
|
|
43
|
+
return new LiveObject(init);
|
|
44
|
+
}
|
|
45
|
+
return obj;
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
function patchLiveObjectKey(liveObject, key, prev, next) {
|
|
49
|
+
if ("production" !== process.env.NODE_ENV) {
|
|
50
|
+
const nonSerializableValue = findNonSerializableValue(next);
|
|
51
|
+
if (nonSerializableValue) return void console.error(`New state path: '${nonSerializableValue.path}' value: '${nonSerializableValue.value}' is not serializable.\nOnly serializable value can be synced with Liveblocks.`);
|
|
52
|
+
}
|
|
53
|
+
const value = liveObject.get(key);
|
|
54
|
+
if (void 0 === next) liveObject.delete(key); else if (void 0 === value) liveObject.set(key, anyToCrdt(next)); else {
|
|
55
|
+
if (prev === next) return;
|
|
56
|
+
value instanceof LiveList && Array.isArray(prev) && Array.isArray(next) ? function(liveList, prev, next) {
|
|
57
|
+
let i = 0, prevEnd = prev.length - 1, nextEnd = next.length - 1, prevNode = prev[0], nextNode = next[0];
|
|
58
|
+
outer: {
|
|
59
|
+
for (;prevNode === nextNode; ) {
|
|
60
|
+
if (++i, i > prevEnd || i > nextEnd) break outer;
|
|
61
|
+
prevNode = prev[i], nextNode = next[i];
|
|
62
|
+
}
|
|
63
|
+
for (prevNode = prev[prevEnd], nextNode = next[nextEnd]; prevNode === nextNode; ) {
|
|
64
|
+
if (prevEnd--, nextEnd--, i > prevEnd || i > nextEnd) break outer;
|
|
65
|
+
prevNode = prev[prevEnd], nextNode = next[nextEnd];
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
if (i > prevEnd) {
|
|
69
|
+
if (i <= nextEnd) for (;i <= nextEnd; ) liveList.insert(anyToCrdt(next[i]), i),
|
|
70
|
+
i++;
|
|
71
|
+
} else if (i > nextEnd) {
|
|
72
|
+
let localI = i;
|
|
73
|
+
for (;localI <= prevEnd; ) liveList.delete(i), localI++;
|
|
74
|
+
} else {
|
|
75
|
+
for (;i <= prevEnd && i <= nextEnd; ) {
|
|
76
|
+
prevNode = prev[i], nextNode = next[i];
|
|
77
|
+
const liveListNode = liveList.get(i);
|
|
78
|
+
liveListNode instanceof LiveObject && isPlainObject(prevNode) && isPlainObject(nextNode) ? patchLiveObject(liveListNode, prevNode, nextNode) : liveList.set(i, anyToCrdt(nextNode)),
|
|
79
|
+
i++;
|
|
80
|
+
}
|
|
81
|
+
for (;i <= nextEnd; ) liveList.insert(anyToCrdt(next[i]), i), i++;
|
|
82
|
+
let localI = i;
|
|
83
|
+
for (;localI <= prevEnd; ) liveList.delete(i), localI++;
|
|
84
|
+
}
|
|
85
|
+
}(value, prev, next) : value instanceof LiveObject && isPlainObject(prev) && isPlainObject(next) ? patchLiveObject(value, prev, next) : liveObject.set(key, anyToCrdt(next));
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
function patchLiveObject(root, prev, next) {
|
|
90
|
+
const updates = {};
|
|
91
|
+
for (const key in next) patchLiveObjectKey(root, key, prev[key], next[key]);
|
|
92
|
+
for (const key in prev) void 0 === next[key] && root.delete(key);
|
|
93
|
+
Object.keys(updates).length > 0 && root.update(updates);
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
function patchImmutableObject(state, updates) {
|
|
97
|
+
return updates.reduce(((state, update) => function(state, update) {
|
|
98
|
+
const path = function(node) {
|
|
99
|
+
const path = [];
|
|
100
|
+
for (;null != node._parentKey && null != node._parent; ) node._parent instanceof LiveList ? path.push(node._parent._indexOfPosition(node._parentKey)) : path.push(node._parentKey),
|
|
101
|
+
node = node._parent;
|
|
102
|
+
return path;
|
|
103
|
+
}(update.node);
|
|
104
|
+
return patchImmutableNode(state, path, update);
|
|
105
|
+
}(state, update)), state);
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
function patchImmutableNode(state, path, update) {
|
|
109
|
+
var _a, _b, _c, _d;
|
|
110
|
+
const pathItem = path.pop();
|
|
111
|
+
if (void 0 === pathItem) switch (update.type) {
|
|
112
|
+
case "LiveObject":
|
|
113
|
+
{
|
|
114
|
+
if ("object" != typeof state) throw new Error("Internal: received update on LiveObject but state was not an object");
|
|
115
|
+
const newState = Object.assign({}, state);
|
|
116
|
+
for (const key in update.updates) if ("update" === (null === (_a = update.updates[key]) || void 0 === _a ? void 0 : _a.type)) {
|
|
117
|
+
const val = update.node.get(key);
|
|
118
|
+
void 0 !== val && (newState[key] = lsonToJson(val));
|
|
119
|
+
} else "delete" === (null === (_b = update.updates[key]) || void 0 === _b ? void 0 : _b.type) && delete newState[key];
|
|
120
|
+
return newState;
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
case "LiveList":
|
|
124
|
+
{
|
|
125
|
+
if (!1 === Array.isArray(state)) throw new Error("Internal: received update on LiveList but state was not an array");
|
|
126
|
+
let newState = state.map((x => x));
|
|
127
|
+
for (const listUpdate of update.updates) "set" === listUpdate.type ? newState = newState.map(((item, index) => index === listUpdate.index ? listUpdate.item : item)) : "insert" === listUpdate.type ? listUpdate.index === newState.length ? newState.push(lsonToJson(listUpdate.item)) : newState = [ ...newState.slice(0, listUpdate.index), lsonToJson(listUpdate.item), ...newState.slice(listUpdate.index) ] : "delete" === listUpdate.type ? newState.splice(listUpdate.index, 1) : "move" === listUpdate.type && (newState = listUpdate.previousIndex > listUpdate.index ? [ ...newState.slice(0, listUpdate.index), lsonToJson(listUpdate.item), ...newState.slice(listUpdate.index, listUpdate.previousIndex), ...newState.slice(listUpdate.previousIndex + 1) ] : [ ...newState.slice(0, listUpdate.previousIndex), ...newState.slice(listUpdate.previousIndex + 1, listUpdate.index + 1), lsonToJson(listUpdate.item), ...newState.slice(listUpdate.index + 1) ]);
|
|
128
|
+
return newState;
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
case "LiveMap":
|
|
132
|
+
{
|
|
133
|
+
if ("object" != typeof state) throw new Error("Internal: received update on LiveMap but state was not an object");
|
|
134
|
+
const newState = Object.assign({}, state);
|
|
135
|
+
for (const key in update.updates) "update" === (null === (_c = update.updates[key]) || void 0 === _c ? void 0 : _c.type) ? newState[key] = lsonToJson(update.node.get(key)) : "delete" === (null === (_d = update.updates[key]) || void 0 === _d ? void 0 : _d.type) && delete newState[key];
|
|
136
|
+
return newState;
|
|
137
|
+
}
|
|
138
|
+
}
|
|
139
|
+
if (Array.isArray(state)) {
|
|
140
|
+
const newArray = [ ...state ];
|
|
141
|
+
return newArray[pathItem] = patchImmutableNode(state[pathItem], path, update), newArray;
|
|
142
|
+
}
|
|
143
|
+
return Object.assign(Object.assign({}, state), {
|
|
144
|
+
[pathItem]: patchImmutableNode(state[pathItem], path, update)
|
|
145
|
+
});
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
export { lsonToJson, patchImmutableObject, patchLiveObjectKey };
|
package/package.json
CHANGED
|
@@ -1,10 +1,22 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@liveblocks/client",
|
|
3
|
-
"version": "0.16.
|
|
3
|
+
"version": "0.16.5",
|
|
4
4
|
"description": "A client that lets you interact with Liveblocks servers.",
|
|
5
5
|
"main": "./index.js",
|
|
6
6
|
"module": "./index.mjs",
|
|
7
7
|
"types": "./index.d.ts",
|
|
8
|
+
"exports": {
|
|
9
|
+
"./internal": {
|
|
10
|
+
"types": "./internal.d.ts",
|
|
11
|
+
"require": "./internal.js",
|
|
12
|
+
"import": "./internal.mjs"
|
|
13
|
+
},
|
|
14
|
+
".": {
|
|
15
|
+
"types": "./index.d.ts",
|
|
16
|
+
"require": "./index.js",
|
|
17
|
+
"import": "./index.mjs"
|
|
18
|
+
}
|
|
19
|
+
},
|
|
8
20
|
"files": [
|
|
9
21
|
"**"
|
|
10
22
|
],
|
|
@@ -19,17 +31,16 @@
|
|
|
19
31
|
},
|
|
20
32
|
"scripts": {
|
|
21
33
|
"build": "rollup -c && cp ./package.json ./README.md ./lib",
|
|
34
|
+
"format": "eslint --fix src/ test/ && prettier --write src/ test/",
|
|
22
35
|
"lint": "eslint src/ test/",
|
|
23
36
|
"test": "jest --watch",
|
|
24
37
|
"test-ci": "jest"
|
|
25
38
|
},
|
|
26
39
|
"license": "Apache-2.0",
|
|
27
40
|
"devDependencies": {
|
|
28
|
-
"@babel/core": "^7.
|
|
29
|
-
"@babel/
|
|
30
|
-
"@babel/
|
|
31
|
-
"@babel/preset-env": "^7.12.16",
|
|
32
|
-
"@babel/preset-typescript": "^7.12.16",
|
|
41
|
+
"@babel/core": "^7.17.10",
|
|
42
|
+
"@babel/preset-env": "^7.17.10",
|
|
43
|
+
"@babel/preset-typescript": "^7.16.7",
|
|
33
44
|
"@rollup/plugin-babel": "^5.3.1",
|
|
34
45
|
"@rollup/plugin-node-resolve": "^13.1.3",
|
|
35
46
|
"@rollup/plugin-replace": "^4.0.0",
|
|
@@ -39,8 +50,9 @@
|
|
|
39
50
|
"@types/ws": "^8.2.2",
|
|
40
51
|
"@typescript-eslint/eslint-plugin": "^5.17.0",
|
|
41
52
|
"@typescript-eslint/parser": "^5.17.0",
|
|
42
|
-
"babel-jest": "^26.6.3",
|
|
43
53
|
"eslint": "^8.12.0",
|
|
54
|
+
"eslint-plugin-import": "^2.26.0",
|
|
55
|
+
"eslint-plugin-simple-import-sort": "^7.0.0",
|
|
44
56
|
"jest": "^26.6.3",
|
|
45
57
|
"jest-each": "^27.5.1",
|
|
46
58
|
"msw": "^0.39.1",
|
|
@@ -48,6 +60,7 @@
|
|
|
48
60
|
"rollup": "^2.68.0",
|
|
49
61
|
"rollup-plugin-command": "^1.1.3",
|
|
50
62
|
"rollup-plugin-dts": "^4.1.0",
|
|
63
|
+
"rollup-plugin-terser": "^7.0.2",
|
|
51
64
|
"typescript": "^4.4.0",
|
|
52
65
|
"whatwg-fetch": "^3.6.2",
|
|
53
66
|
"ws": "^8.5.0"
|
package/shared.d.ts
CHANGED
|
@@ -22,7 +22,11 @@ declare type JsonObject = {
|
|
|
22
22
|
*/
|
|
23
23
|
declare class LiveMap<TKey extends string = string, TValue extends Lson = Lson> extends AbstractCrdt {
|
|
24
24
|
private _map;
|
|
25
|
-
constructor(entries?: readonly (readonly [TKey, TValue])[] |
|
|
25
|
+
constructor(entries?: readonly (readonly [TKey, TValue])[] | undefined);
|
|
26
|
+
/**
|
|
27
|
+
* @deprecated Please call as `new LiveMap()` or `new LiveMap([])` instead.
|
|
28
|
+
*/
|
|
29
|
+
constructor(entries: null);
|
|
26
30
|
/**
|
|
27
31
|
* Returns a specified element from the LiveMap.
|
|
28
32
|
* @param key The key of the element to return.
|
|
@@ -291,6 +295,27 @@ declare type BroadcastOptions = {
|
|
|
291
295
|
* in-client.
|
|
292
296
|
*/
|
|
293
297
|
declare type StorageUpdate = LiveMapUpdates<string, Lson> | LiveObjectUpdates<LsonObject> | LiveListUpdates<Lson>;
|
|
298
|
+
declare type RoomInitializers<TPresence, TStorage> = Resolve<{
|
|
299
|
+
/**
|
|
300
|
+
* The initial Presence to use and announce when you enter the Room. The
|
|
301
|
+
* Presence is available on all users in the Room (me & others).
|
|
302
|
+
*/
|
|
303
|
+
initialPresence?: TPresence | ((roomId: string) => TPresence);
|
|
304
|
+
/**
|
|
305
|
+
* The initial Storage to use when entering a new Room.
|
|
306
|
+
*/
|
|
307
|
+
initialStorage?: TStorage | ((roomId: string) => TStorage);
|
|
308
|
+
/**
|
|
309
|
+
* @deprecated Please use `initialPresence` instead. This property is
|
|
310
|
+
* scheduled for removal in 0.18.
|
|
311
|
+
*/
|
|
312
|
+
defaultPresence?: () => TPresence;
|
|
313
|
+
/**
|
|
314
|
+
* @deprecated Please use `initialStorage` instead. This property is
|
|
315
|
+
* scheduled for removal in 0.18.
|
|
316
|
+
*/
|
|
317
|
+
defaultStorageRoot?: TStorage;
|
|
318
|
+
}>;
|
|
294
319
|
declare type Client = {
|
|
295
320
|
/**
|
|
296
321
|
* Gets a room. Returns null if {@link Client.enter} has not been called previously.
|
|
@@ -301,12 +326,9 @@ declare type Client = {
|
|
|
301
326
|
/**
|
|
302
327
|
* Enters a room and returns it.
|
|
303
328
|
* @param roomId The id of the room
|
|
304
|
-
* @param
|
|
329
|
+
* @param options Optional. You can provide initializers for the Presence or Storage when entering the Room.
|
|
305
330
|
*/
|
|
306
|
-
enter<TStorage extends Record<string, any> = Record<string, any>>(roomId: string, options?:
|
|
307
|
-
defaultPresence?: Presence;
|
|
308
|
-
defaultStorageRoot?: TStorage;
|
|
309
|
-
}): Room;
|
|
331
|
+
enter<TStorage extends Record<string, any> = Record<string, any>>(roomId: string, options?: RoomInitializers<Presence, TStorage>): Room;
|
|
310
332
|
/**
|
|
311
333
|
* Leaves a room.
|
|
312
334
|
* @param roomId The id of the room
|
|
@@ -376,7 +398,15 @@ declare type ClientOptions = {
|
|
|
376
398
|
publicApiKey?: never;
|
|
377
399
|
authEndpoint: AuthEndpoint;
|
|
378
400
|
});
|
|
379
|
-
declare type
|
|
401
|
+
declare type Connection = {
|
|
402
|
+
state: "closed" | "authenticating" | "unavailable" | "failed";
|
|
403
|
+
} | {
|
|
404
|
+
state: "open" | "connecting";
|
|
405
|
+
id: number;
|
|
406
|
+
userId?: string;
|
|
407
|
+
userInfo?: any;
|
|
408
|
+
};
|
|
409
|
+
declare type ConnectionState = Connection["state"];
|
|
380
410
|
declare type OthersEvent<T extends Presence = Presence> = {
|
|
381
411
|
type: "leave";
|
|
382
412
|
user: User<T>;
|
|
@@ -720,7 +750,7 @@ declare abstract class AbstractCrdt {
|
|
|
720
750
|
declare class LiveObject<O extends LsonObject = LsonObject> extends AbstractCrdt {
|
|
721
751
|
private _map;
|
|
722
752
|
private _propToLastUpdate;
|
|
723
|
-
constructor(
|
|
753
|
+
constructor(obj?: O);
|
|
724
754
|
private _applyUpdate;
|
|
725
755
|
private _applyDeleteObjectKey;
|
|
726
756
|
/**
|
|
@@ -750,4 +780,4 @@ declare class LiveObject<O extends LsonObject = LsonObject> extends AbstractCrdt
|
|
|
750
780
|
update(overrides: Partial<O>): void;
|
|
751
781
|
}
|
|
752
782
|
|
|
753
|
-
export { BroadcastOptions as B, ClientOptions as C, History as H, Json as J, LiveObject as L, Others as O, Presence as P, Room as R, StorageUpdate as S, User as U, Client as a, LiveMap as b, LiveList as c, JsonObject as d, Lson as e, LsonObject as f, Resolve as g };
|
|
783
|
+
export { AbstractCrdt as A, BroadcastOptions as B, ClientOptions as C, History as H, Json as J, LiveObject as L, Others as O, Presence as P, Room as R, StorageUpdate as S, User as U, Client as a, LiveMap as b, LiveList as c, JsonObject as d, Lson as e, LsonObject as f, Resolve as g, RoomInitializers as h };
|