@liveblocks/client 0.16.1 → 0.16.4-beta1
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.d.ts +31 -0
- package/index.js +1924 -0
- package/index.mjs +1641 -0
- package/{lib/internal.d.ts → internal.d.ts} +15 -19
- package/internal.js +36 -0
- package/internal.mjs +1 -0
- package/package.json +11 -22
- package/{lib/index.d.ts → shared.d.ts} +32 -34
- package/{lib/index.js → shared.js} +117 -1968
- package/shared.mjs +1947 -0
- package/lib/esm/index.js +0 -3054
- package/lib/esm/index.mjs +0 -3054
- package/lib/esm/internal.js +0 -150
- package/lib/esm/internal.mjs +0 -150
- package/lib/internal.js +0 -194
package/index.js
ADDED
|
@@ -0,0 +1,1924 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
Object.defineProperty(exports, '__esModule', { value: true });
|
|
4
|
+
|
|
5
|
+
var LiveObject = require('./shared.js');
|
|
6
|
+
|
|
7
|
+
var BACKOFF_RETRY_DELAYS = [250, 500, 1000, 2000, 4000, 8000, 10000];
|
|
8
|
+
var BACKOFF_RETRY_DELAYS_SLOW = [2000, 30000, 60000, 300000];
|
|
9
|
+
var HEARTBEAT_INTERVAL = 30000;
|
|
10
|
+
var PONG_TIMEOUT = 2000;
|
|
11
|
+
|
|
12
|
+
function isValidRoomEventType(value) {
|
|
13
|
+
return value === "my-presence" || value === "others" || value === "event" || value === "error" || value === "connection";
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
function makeIdFactory(connectionId) {
|
|
17
|
+
var count = 0;
|
|
18
|
+
return function () {
|
|
19
|
+
return connectionId + ":" + count++;
|
|
20
|
+
};
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
function makeOthers(userMap) {
|
|
24
|
+
var _ref;
|
|
25
|
+
|
|
26
|
+
var users = Object.values(userMap).map(function (user) {
|
|
27
|
+
user._hasReceivedInitialPresence;
|
|
28
|
+
var publicKeys = LiveObject._objectWithoutPropertiesLoose(user, ["_hasReceivedInitialPresence"]);
|
|
29
|
+
|
|
30
|
+
return publicKeys;
|
|
31
|
+
});
|
|
32
|
+
return _ref = {
|
|
33
|
+
get count() {
|
|
34
|
+
return users.length;
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
}, _ref[Symbol.iterator] = function () {
|
|
38
|
+
return users[Symbol.iterator]();
|
|
39
|
+
}, _ref.map = function map(callback) {
|
|
40
|
+
return users.map(callback);
|
|
41
|
+
}, _ref.toArray = function toArray() {
|
|
42
|
+
return users;
|
|
43
|
+
}, _ref;
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
function makeStateMachine(state, context, mockedEffects) {
|
|
47
|
+
var effects = mockedEffects || {
|
|
48
|
+
authenticate: function authenticate(auth, createWebSocket) {
|
|
49
|
+
var token = state.token;
|
|
50
|
+
|
|
51
|
+
if (token && LiveObject.isTokenValid(token)) {
|
|
52
|
+
var parsedToken = parseToken(token);
|
|
53
|
+
var socket = createWebSocket(token);
|
|
54
|
+
authenticationSuccess(parsedToken, socket);
|
|
55
|
+
} else {
|
|
56
|
+
return auth(context.roomId).then(function (_ref2) {
|
|
57
|
+
var token = _ref2.token;
|
|
58
|
+
|
|
59
|
+
if (state.connection.state !== "authenticating") {
|
|
60
|
+
return;
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
var parsedToken = parseToken(token);
|
|
64
|
+
var socket = createWebSocket(token);
|
|
65
|
+
authenticationSuccess(parsedToken, socket);
|
|
66
|
+
state.token = token;
|
|
67
|
+
}).catch(function (er) {
|
|
68
|
+
return authenticationFailure(er);
|
|
69
|
+
});
|
|
70
|
+
}
|
|
71
|
+
},
|
|
72
|
+
send: function send(messageOrMessages) {
|
|
73
|
+
if (state.socket == null) {
|
|
74
|
+
throw new Error("Can't send message if socket is null");
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
state.socket.send(JSON.stringify(messageOrMessages));
|
|
78
|
+
},
|
|
79
|
+
delayFlush: function delayFlush(delay) {
|
|
80
|
+
return setTimeout(tryFlushing, delay);
|
|
81
|
+
},
|
|
82
|
+
startHeartbeatInterval: function startHeartbeatInterval() {
|
|
83
|
+
return setInterval(heartbeat, HEARTBEAT_INTERVAL);
|
|
84
|
+
},
|
|
85
|
+
schedulePongTimeout: function schedulePongTimeout() {
|
|
86
|
+
return setTimeout(pongTimeout, PONG_TIMEOUT);
|
|
87
|
+
},
|
|
88
|
+
scheduleReconnect: function scheduleReconnect(delay) {
|
|
89
|
+
return setTimeout(connect, delay);
|
|
90
|
+
}
|
|
91
|
+
};
|
|
92
|
+
|
|
93
|
+
function genericSubscribe(callback) {
|
|
94
|
+
state.listeners.storage.push(callback);
|
|
95
|
+
return function () {
|
|
96
|
+
return LiveObject.remove(state.listeners.storage, callback);
|
|
97
|
+
};
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
function crdtSubscribe(crdt, innerCallback, options) {
|
|
101
|
+
var cb = function cb(updates) {
|
|
102
|
+
var relatedUpdates = [];
|
|
103
|
+
|
|
104
|
+
for (var _iterator = LiveObject._createForOfIteratorHelperLoose(updates), _step; !(_step = _iterator()).done;) {
|
|
105
|
+
var update = _step.value;
|
|
106
|
+
|
|
107
|
+
if (options != null && options.isDeep && LiveObject.isSameNodeOrChildOf(update.node, crdt)) {
|
|
108
|
+
relatedUpdates.push(update);
|
|
109
|
+
} else if (update.node._id === crdt._id) {
|
|
110
|
+
innerCallback(update.node);
|
|
111
|
+
}
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
if (options != null && options.isDeep && relatedUpdates.length > 0) {
|
|
115
|
+
innerCallback(relatedUpdates);
|
|
116
|
+
}
|
|
117
|
+
};
|
|
118
|
+
|
|
119
|
+
return genericSubscribe(cb);
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
function createOrUpdateRootFromMessage(message) {
|
|
123
|
+
if (message.items.length === 0) {
|
|
124
|
+
throw new Error("Internal error: cannot load storage without items");
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
if (state.root) {
|
|
128
|
+
updateRoot(message.items);
|
|
129
|
+
} else {
|
|
130
|
+
state.root = load(message.items);
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
for (var _key in state.defaultStorageRoot) {
|
|
134
|
+
if (state.root.get(_key) == null) {
|
|
135
|
+
state.root.set(_key, state.defaultStorageRoot[_key]);
|
|
136
|
+
}
|
|
137
|
+
}
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
function buildRootAndParentToChildren(items) {
|
|
141
|
+
var parentToChildren = new Map();
|
|
142
|
+
var root = null;
|
|
143
|
+
|
|
144
|
+
for (var _iterator2 = LiveObject._createForOfIteratorHelperLoose(items), _step2; !(_step2 = _iterator2()).done;) {
|
|
145
|
+
var tuple = _step2.value;
|
|
146
|
+
var parentId = tuple[1].parentId;
|
|
147
|
+
|
|
148
|
+
if (parentId == null) {
|
|
149
|
+
root = tuple;
|
|
150
|
+
} else {
|
|
151
|
+
var children = parentToChildren.get(parentId);
|
|
152
|
+
|
|
153
|
+
if (children != null) {
|
|
154
|
+
children.push(tuple);
|
|
155
|
+
} else {
|
|
156
|
+
parentToChildren.set(parentId, [tuple]);
|
|
157
|
+
}
|
|
158
|
+
}
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
if (root == null) {
|
|
162
|
+
throw new Error("Root can't be null");
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
return [root, parentToChildren];
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
function updateRoot(items) {
|
|
169
|
+
if (!state.root) {
|
|
170
|
+
return;
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
var currentItems = new Map();
|
|
174
|
+
state.items.forEach(function (liveCrdt, id) {
|
|
175
|
+
currentItems.set(id, liveCrdt._toSerializedCrdt());
|
|
176
|
+
});
|
|
177
|
+
var ops = LiveObject.getTreesDiffOperations(currentItems, new Map(items));
|
|
178
|
+
var result = apply(ops, false);
|
|
179
|
+
notify(result.updates);
|
|
180
|
+
}
|
|
181
|
+
|
|
182
|
+
function load(items) {
|
|
183
|
+
var _buildRootAndParentTo = buildRootAndParentToChildren(items),
|
|
184
|
+
root = _buildRootAndParentTo[0],
|
|
185
|
+
parentToChildren = _buildRootAndParentTo[1];
|
|
186
|
+
|
|
187
|
+
return LiveObject.LiveObject._deserialize(root, parentToChildren, {
|
|
188
|
+
getItem: getItem,
|
|
189
|
+
addItem: addItem,
|
|
190
|
+
deleteItem: deleteItem,
|
|
191
|
+
generateId: generateId,
|
|
192
|
+
generateOpId: generateOpId,
|
|
193
|
+
dispatch: storageDispatch,
|
|
194
|
+
roomId: context.roomId
|
|
195
|
+
});
|
|
196
|
+
}
|
|
197
|
+
|
|
198
|
+
function addItem(id, item) {
|
|
199
|
+
state.items.set(id, item);
|
|
200
|
+
}
|
|
201
|
+
|
|
202
|
+
function deleteItem(id) {
|
|
203
|
+
state.items.delete(id);
|
|
204
|
+
}
|
|
205
|
+
|
|
206
|
+
function getItem(id) {
|
|
207
|
+
return state.items.get(id);
|
|
208
|
+
}
|
|
209
|
+
|
|
210
|
+
function addToUndoStack(historyItem) {
|
|
211
|
+
if (state.undoStack.length >= 50) {
|
|
212
|
+
state.undoStack.shift();
|
|
213
|
+
}
|
|
214
|
+
|
|
215
|
+
if (state.isHistoryPaused) {
|
|
216
|
+
var _state$pausedHistory;
|
|
217
|
+
|
|
218
|
+
(_state$pausedHistory = state.pausedHistory).unshift.apply(_state$pausedHistory, historyItem);
|
|
219
|
+
} else {
|
|
220
|
+
state.undoStack.push(historyItem);
|
|
221
|
+
}
|
|
222
|
+
}
|
|
223
|
+
|
|
224
|
+
function storageDispatch(ops, reverse, storageUpdates) {
|
|
225
|
+
if (state.isBatching) {
|
|
226
|
+
var _state$batch$ops, _state$batch$reverseO;
|
|
227
|
+
|
|
228
|
+
(_state$batch$ops = state.batch.ops).push.apply(_state$batch$ops, ops);
|
|
229
|
+
|
|
230
|
+
storageUpdates.forEach(function (value, key) {
|
|
231
|
+
state.batch.updates.storageUpdates.set(key, LiveObject.mergeStorageUpdates(state.batch.updates.storageUpdates.get(key), value));
|
|
232
|
+
});
|
|
233
|
+
|
|
234
|
+
(_state$batch$reverseO = state.batch.reverseOps).push.apply(_state$batch$reverseO, reverse);
|
|
235
|
+
} else {
|
|
236
|
+
addToUndoStack(reverse);
|
|
237
|
+
state.redoStack = [];
|
|
238
|
+
dispatch(ops);
|
|
239
|
+
notify({
|
|
240
|
+
storageUpdates: storageUpdates
|
|
241
|
+
});
|
|
242
|
+
}
|
|
243
|
+
}
|
|
244
|
+
|
|
245
|
+
function notify(_ref3) {
|
|
246
|
+
var _ref3$storageUpdates = _ref3.storageUpdates,
|
|
247
|
+
storageUpdates = _ref3$storageUpdates === void 0 ? new Map() : _ref3$storageUpdates,
|
|
248
|
+
_ref3$presence = _ref3.presence,
|
|
249
|
+
presence = _ref3$presence === void 0 ? false : _ref3$presence,
|
|
250
|
+
_ref3$others = _ref3.others,
|
|
251
|
+
otherEvents = _ref3$others === void 0 ? [] : _ref3$others;
|
|
252
|
+
|
|
253
|
+
if (otherEvents.length > 0) {
|
|
254
|
+
state.others = makeOthers(state.users);
|
|
255
|
+
|
|
256
|
+
for (var _iterator3 = LiveObject._createForOfIteratorHelperLoose(otherEvents), _step3; !(_step3 = _iterator3()).done;) {
|
|
257
|
+
var event = _step3.value;
|
|
258
|
+
|
|
259
|
+
for (var _iterator4 = LiveObject._createForOfIteratorHelperLoose(state.listeners.others), _step4; !(_step4 = _iterator4()).done;) {
|
|
260
|
+
var _listener = _step4.value;
|
|
261
|
+
|
|
262
|
+
_listener(state.others, event);
|
|
263
|
+
}
|
|
264
|
+
}
|
|
265
|
+
}
|
|
266
|
+
|
|
267
|
+
if (presence) {
|
|
268
|
+
for (var _iterator5 = LiveObject._createForOfIteratorHelperLoose(state.listeners["my-presence"]), _step5; !(_step5 = _iterator5()).done;) {
|
|
269
|
+
var _listener2 = _step5.value;
|
|
270
|
+
|
|
271
|
+
_listener2(state.me);
|
|
272
|
+
}
|
|
273
|
+
}
|
|
274
|
+
|
|
275
|
+
if (storageUpdates.size > 0) {
|
|
276
|
+
for (var _iterator6 = LiveObject._createForOfIteratorHelperLoose(state.listeners.storage), _step6; !(_step6 = _iterator6()).done;) {
|
|
277
|
+
var subscriber = _step6.value;
|
|
278
|
+
subscriber(Array.from(storageUpdates.values()));
|
|
279
|
+
}
|
|
280
|
+
}
|
|
281
|
+
}
|
|
282
|
+
|
|
283
|
+
function getConnectionId() {
|
|
284
|
+
if (state.connection.state === "open" || state.connection.state === "connecting") {
|
|
285
|
+
return state.connection.id;
|
|
286
|
+
} else if (state.lastConnectionId !== null) {
|
|
287
|
+
return state.lastConnectionId;
|
|
288
|
+
}
|
|
289
|
+
|
|
290
|
+
throw new Error("Internal. Tried to get connection id but connection was never open");
|
|
291
|
+
}
|
|
292
|
+
|
|
293
|
+
function generateId() {
|
|
294
|
+
return getConnectionId() + ":" + state.clock++;
|
|
295
|
+
}
|
|
296
|
+
|
|
297
|
+
function generateOpId() {
|
|
298
|
+
return getConnectionId() + ":" + state.opClock++;
|
|
299
|
+
}
|
|
300
|
+
|
|
301
|
+
function apply(item, isLocal) {
|
|
302
|
+
var result = {
|
|
303
|
+
reverse: [],
|
|
304
|
+
updates: {
|
|
305
|
+
storageUpdates: new Map(),
|
|
306
|
+
presence: false
|
|
307
|
+
}
|
|
308
|
+
};
|
|
309
|
+
var createdNodeIds = new Set();
|
|
310
|
+
|
|
311
|
+
for (var _iterator7 = LiveObject._createForOfIteratorHelperLoose(item), _step7; !(_step7 = _iterator7()).done;) {
|
|
312
|
+
var op = _step7.value;
|
|
313
|
+
|
|
314
|
+
if (op.type === "presence") {
|
|
315
|
+
var reverse = {
|
|
316
|
+
type: "presence",
|
|
317
|
+
data: {}
|
|
318
|
+
};
|
|
319
|
+
|
|
320
|
+
for (var _key2 in op.data) {
|
|
321
|
+
reverse.data[_key2] = state.me[_key2];
|
|
322
|
+
}
|
|
323
|
+
|
|
324
|
+
state.me = LiveObject._extends({}, state.me, op.data);
|
|
325
|
+
|
|
326
|
+
if (state.buffer.presence == null) {
|
|
327
|
+
state.buffer.presence = op.data;
|
|
328
|
+
} else {
|
|
329
|
+
for (var _key3 in op.data) {
|
|
330
|
+
state.buffer.presence[_key3] = op.data[_key3];
|
|
331
|
+
}
|
|
332
|
+
}
|
|
333
|
+
|
|
334
|
+
result.reverse.unshift(reverse);
|
|
335
|
+
result.updates.presence = true;
|
|
336
|
+
} else {
|
|
337
|
+
if (isLocal && !op.opId) {
|
|
338
|
+
op.opId = generateOpId();
|
|
339
|
+
}
|
|
340
|
+
|
|
341
|
+
var applyOpResult = applyOp(op, isLocal);
|
|
342
|
+
|
|
343
|
+
if (applyOpResult.modified) {
|
|
344
|
+
var _applyOpResult$modifi;
|
|
345
|
+
|
|
346
|
+
var parentId = (_applyOpResult$modifi = applyOpResult.modified.node._parent) == null ? void 0 : _applyOpResult$modifi._id;
|
|
347
|
+
|
|
348
|
+
if (!createdNodeIds.has(parentId)) {
|
|
349
|
+
var _result$reverse;
|
|
350
|
+
|
|
351
|
+
result.updates.storageUpdates.set(applyOpResult.modified.node._id, LiveObject.mergeStorageUpdates(result.updates.storageUpdates.get(applyOpResult.modified.node._id), applyOpResult.modified));
|
|
352
|
+
|
|
353
|
+
(_result$reverse = result.reverse).unshift.apply(_result$reverse, applyOpResult.reverse);
|
|
354
|
+
}
|
|
355
|
+
|
|
356
|
+
if (op.type === LiveObject.OpType.CreateList || op.type === LiveObject.OpType.CreateMap || op.type === LiveObject.OpType.CreateObject) {
|
|
357
|
+
createdNodeIds.add(applyOpResult.modified.node._id);
|
|
358
|
+
}
|
|
359
|
+
}
|
|
360
|
+
}
|
|
361
|
+
}
|
|
362
|
+
|
|
363
|
+
return result;
|
|
364
|
+
}
|
|
365
|
+
|
|
366
|
+
function applyOp(op, isLocal) {
|
|
367
|
+
if (op.opId) {
|
|
368
|
+
state.offlineOperations.delete(op.opId);
|
|
369
|
+
}
|
|
370
|
+
|
|
371
|
+
switch (op.type) {
|
|
372
|
+
case LiveObject.OpType.DeleteObjectKey:
|
|
373
|
+
case LiveObject.OpType.UpdateObject:
|
|
374
|
+
case LiveObject.OpType.DeleteCrdt:
|
|
375
|
+
{
|
|
376
|
+
var item = state.items.get(op.id);
|
|
377
|
+
|
|
378
|
+
if (item == null) {
|
|
379
|
+
return {
|
|
380
|
+
modified: false
|
|
381
|
+
};
|
|
382
|
+
}
|
|
383
|
+
|
|
384
|
+
return item._apply(op, isLocal);
|
|
385
|
+
}
|
|
386
|
+
|
|
387
|
+
case LiveObject.OpType.SetParentKey:
|
|
388
|
+
{
|
|
389
|
+
var _item = state.items.get(op.id);
|
|
390
|
+
|
|
391
|
+
if (_item == null) {
|
|
392
|
+
return {
|
|
393
|
+
modified: false
|
|
394
|
+
};
|
|
395
|
+
}
|
|
396
|
+
|
|
397
|
+
if (_item._parent instanceof LiveObject.LiveList) {
|
|
398
|
+
var previousKey = _item._parentKey;
|
|
399
|
+
|
|
400
|
+
if (previousKey === op.parentKey) {
|
|
401
|
+
return {
|
|
402
|
+
modified: false
|
|
403
|
+
};
|
|
404
|
+
} else {
|
|
405
|
+
return _item._parent._setChildKey(op.parentKey, _item, previousKey);
|
|
406
|
+
}
|
|
407
|
+
}
|
|
408
|
+
|
|
409
|
+
return {
|
|
410
|
+
modified: false
|
|
411
|
+
};
|
|
412
|
+
}
|
|
413
|
+
|
|
414
|
+
case LiveObject.OpType.CreateObject:
|
|
415
|
+
case LiveObject.OpType.CreateList:
|
|
416
|
+
case LiveObject.OpType.CreateMap:
|
|
417
|
+
case LiveObject.OpType.CreateRegister:
|
|
418
|
+
{
|
|
419
|
+
var parent = state.items.get(op.parentId);
|
|
420
|
+
|
|
421
|
+
if (parent == null) {
|
|
422
|
+
return {
|
|
423
|
+
modified: false
|
|
424
|
+
};
|
|
425
|
+
}
|
|
426
|
+
|
|
427
|
+
return parent._attachChild(op, isLocal);
|
|
428
|
+
}
|
|
429
|
+
}
|
|
430
|
+
}
|
|
431
|
+
|
|
432
|
+
function subscribe(firstParam, listener, options) {
|
|
433
|
+
if (firstParam instanceof LiveObject.AbstractCrdt) {
|
|
434
|
+
return crdtSubscribe(firstParam, listener, options);
|
|
435
|
+
} else if (typeof firstParam === "function") {
|
|
436
|
+
return genericSubscribe(firstParam);
|
|
437
|
+
} else if (!isValidRoomEventType(firstParam)) {
|
|
438
|
+
throw new Error("\"" + firstParam + "\" is not a valid event name");
|
|
439
|
+
}
|
|
440
|
+
|
|
441
|
+
state.listeners[firstParam].push(listener);
|
|
442
|
+
return function () {
|
|
443
|
+
var callbacks = state.listeners[firstParam];
|
|
444
|
+
LiveObject.remove(callbacks, listener);
|
|
445
|
+
};
|
|
446
|
+
}
|
|
447
|
+
|
|
448
|
+
function unsubscribe(event, callback) {
|
|
449
|
+
console.warn("unsubscribe is depreacted and will be removed in a future version.\nuse the callback returned by subscribe instead.\nSee v0.13 release notes for more information.\n");
|
|
450
|
+
|
|
451
|
+
if (!isValidRoomEventType(event)) {
|
|
452
|
+
throw new Error("\"" + event + "\" is not a valid event name");
|
|
453
|
+
}
|
|
454
|
+
|
|
455
|
+
var callbacks = state.listeners[event];
|
|
456
|
+
LiveObject.remove(callbacks, callback);
|
|
457
|
+
}
|
|
458
|
+
|
|
459
|
+
function getConnectionState() {
|
|
460
|
+
return state.connection.state;
|
|
461
|
+
}
|
|
462
|
+
|
|
463
|
+
function getSelf() {
|
|
464
|
+
return state.connection.state === "open" || state.connection.state === "connecting" ? {
|
|
465
|
+
connectionId: state.connection.id,
|
|
466
|
+
id: state.connection.userId,
|
|
467
|
+
info: state.connection.userInfo,
|
|
468
|
+
presence: getPresence()
|
|
469
|
+
} : null;
|
|
470
|
+
}
|
|
471
|
+
|
|
472
|
+
function connect() {
|
|
473
|
+
if (state.connection.state !== "closed" && state.connection.state !== "unavailable") {
|
|
474
|
+
return null;
|
|
475
|
+
}
|
|
476
|
+
|
|
477
|
+
var auth = prepareAuthEndpoint(context.authentication, context.fetchPolyfill);
|
|
478
|
+
var createWebSocket = prepareCreateWebSocket(context.liveblocksServer, context.WebSocketPolyfill);
|
|
479
|
+
updateConnection({
|
|
480
|
+
state: "authenticating"
|
|
481
|
+
});
|
|
482
|
+
effects.authenticate(auth, createWebSocket);
|
|
483
|
+
}
|
|
484
|
+
|
|
485
|
+
function updatePresence(overrides, options) {
|
|
486
|
+
var oldValues = {};
|
|
487
|
+
|
|
488
|
+
if (state.buffer.presence == null) {
|
|
489
|
+
state.buffer.presence = {};
|
|
490
|
+
}
|
|
491
|
+
|
|
492
|
+
for (var _key4 in overrides) {
|
|
493
|
+
state.buffer.presence[_key4] = overrides[_key4];
|
|
494
|
+
oldValues[_key4] = state.me[_key4];
|
|
495
|
+
}
|
|
496
|
+
|
|
497
|
+
state.me = LiveObject._extends({}, state.me, overrides);
|
|
498
|
+
|
|
499
|
+
if (state.isBatching) {
|
|
500
|
+
if (options != null && options.addToHistory) {
|
|
501
|
+
state.batch.reverseOps.push({
|
|
502
|
+
type: "presence",
|
|
503
|
+
data: oldValues
|
|
504
|
+
});
|
|
505
|
+
}
|
|
506
|
+
|
|
507
|
+
state.batch.updates.presence = true;
|
|
508
|
+
} else {
|
|
509
|
+
tryFlushing();
|
|
510
|
+
|
|
511
|
+
if (options != null && options.addToHistory) {
|
|
512
|
+
addToUndoStack([{
|
|
513
|
+
type: "presence",
|
|
514
|
+
data: oldValues
|
|
515
|
+
}]);
|
|
516
|
+
}
|
|
517
|
+
|
|
518
|
+
notify({
|
|
519
|
+
presence: true
|
|
520
|
+
});
|
|
521
|
+
}
|
|
522
|
+
}
|
|
523
|
+
|
|
524
|
+
function authenticationSuccess(token, socket) {
|
|
525
|
+
socket.addEventListener("message", onMessage);
|
|
526
|
+
socket.addEventListener("open", onOpen);
|
|
527
|
+
socket.addEventListener("close", onClose);
|
|
528
|
+
socket.addEventListener("error", onError);
|
|
529
|
+
updateConnection({
|
|
530
|
+
state: "connecting",
|
|
531
|
+
id: token.actor,
|
|
532
|
+
userInfo: token.info,
|
|
533
|
+
userId: token.id
|
|
534
|
+
});
|
|
535
|
+
state.idFactory = makeIdFactory(token.actor);
|
|
536
|
+
state.socket = socket;
|
|
537
|
+
}
|
|
538
|
+
|
|
539
|
+
function authenticationFailure(error) {
|
|
540
|
+
if (process.env.NODE_ENV !== "production") {
|
|
541
|
+
console.error("Call to authentication endpoint failed", error);
|
|
542
|
+
}
|
|
543
|
+
|
|
544
|
+
state.token = null;
|
|
545
|
+
updateConnection({
|
|
546
|
+
state: "unavailable"
|
|
547
|
+
});
|
|
548
|
+
state.numberOfRetry++;
|
|
549
|
+
state.timeoutHandles.reconnect = effects.scheduleReconnect(getRetryDelay());
|
|
550
|
+
}
|
|
551
|
+
|
|
552
|
+
function onVisibilityChange(visibilityState) {
|
|
553
|
+
if (visibilityState === "visible" && state.connection.state === "open") {
|
|
554
|
+
heartbeat();
|
|
555
|
+
}
|
|
556
|
+
}
|
|
557
|
+
|
|
558
|
+
function onUpdatePresenceMessage(message) {
|
|
559
|
+
var user = state.users[message.actor];
|
|
560
|
+
|
|
561
|
+
if (message.targetActor === undefined && user != null && !user._hasReceivedInitialPresence) {
|
|
562
|
+
return undefined;
|
|
563
|
+
}
|
|
564
|
+
|
|
565
|
+
if (user == null) {
|
|
566
|
+
state.users[message.actor] = {
|
|
567
|
+
connectionId: message.actor,
|
|
568
|
+
presence: message.data,
|
|
569
|
+
_hasReceivedInitialPresence: true
|
|
570
|
+
};
|
|
571
|
+
} else {
|
|
572
|
+
state.users[message.actor] = {
|
|
573
|
+
id: user.id,
|
|
574
|
+
info: user.info,
|
|
575
|
+
connectionId: message.actor,
|
|
576
|
+
presence: LiveObject._extends({}, user.presence, message.data),
|
|
577
|
+
_hasReceivedInitialPresence: true
|
|
578
|
+
};
|
|
579
|
+
}
|
|
580
|
+
|
|
581
|
+
return {
|
|
582
|
+
type: "update",
|
|
583
|
+
updates: message.data,
|
|
584
|
+
user: state.users[message.actor]
|
|
585
|
+
};
|
|
586
|
+
}
|
|
587
|
+
|
|
588
|
+
function onUserLeftMessage(message) {
|
|
589
|
+
var userLeftMessage = message;
|
|
590
|
+
var user = state.users[userLeftMessage.actor];
|
|
591
|
+
|
|
592
|
+
if (user) {
|
|
593
|
+
delete state.users[userLeftMessage.actor];
|
|
594
|
+
return {
|
|
595
|
+
type: "leave",
|
|
596
|
+
user: user
|
|
597
|
+
};
|
|
598
|
+
}
|
|
599
|
+
|
|
600
|
+
return null;
|
|
601
|
+
}
|
|
602
|
+
|
|
603
|
+
function onRoomStateMessage(message) {
|
|
604
|
+
var newUsers = {};
|
|
605
|
+
|
|
606
|
+
for (var _key5 in message.users) {
|
|
607
|
+
var _connectionId = Number.parseInt(_key5);
|
|
608
|
+
|
|
609
|
+
var user = message.users[_key5];
|
|
610
|
+
newUsers[_connectionId] = {
|
|
611
|
+
connectionId: _connectionId,
|
|
612
|
+
info: user.info,
|
|
613
|
+
id: user.id
|
|
614
|
+
};
|
|
615
|
+
}
|
|
616
|
+
|
|
617
|
+
state.users = newUsers;
|
|
618
|
+
return {
|
|
619
|
+
type: "reset"
|
|
620
|
+
};
|
|
621
|
+
}
|
|
622
|
+
|
|
623
|
+
function onNavigatorOnline() {
|
|
624
|
+
if (state.connection.state === "unavailable") {
|
|
625
|
+
reconnect();
|
|
626
|
+
}
|
|
627
|
+
}
|
|
628
|
+
|
|
629
|
+
function onEvent(message) {
|
|
630
|
+
for (var _iterator8 = LiveObject._createForOfIteratorHelperLoose(state.listeners.event), _step8; !(_step8 = _iterator8()).done;) {
|
|
631
|
+
var _listener3 = _step8.value;
|
|
632
|
+
|
|
633
|
+
_listener3({
|
|
634
|
+
connectionId: message.actor,
|
|
635
|
+
event: message.event
|
|
636
|
+
});
|
|
637
|
+
}
|
|
638
|
+
}
|
|
639
|
+
|
|
640
|
+
function onUserJoinedMessage(message) {
|
|
641
|
+
state.users[message.actor] = {
|
|
642
|
+
connectionId: message.actor,
|
|
643
|
+
info: message.info,
|
|
644
|
+
id: message.id,
|
|
645
|
+
_hasReceivedInitialPresence: true
|
|
646
|
+
};
|
|
647
|
+
|
|
648
|
+
if (state.me) {
|
|
649
|
+
state.buffer.messages.push({
|
|
650
|
+
type: LiveObject.ClientMessageType.UpdatePresence,
|
|
651
|
+
data: state.me,
|
|
652
|
+
targetActor: message.actor
|
|
653
|
+
});
|
|
654
|
+
tryFlushing();
|
|
655
|
+
}
|
|
656
|
+
|
|
657
|
+
return {
|
|
658
|
+
type: "enter",
|
|
659
|
+
user: state.users[message.actor]
|
|
660
|
+
};
|
|
661
|
+
}
|
|
662
|
+
|
|
663
|
+
function parseServerMessage(data) {
|
|
664
|
+
if (!LiveObject.isJsonObject(data)) {
|
|
665
|
+
return null;
|
|
666
|
+
}
|
|
667
|
+
|
|
668
|
+
return data;
|
|
669
|
+
}
|
|
670
|
+
|
|
671
|
+
function parseServerMessages(text) {
|
|
672
|
+
var data = LiveObject.parseJson(text);
|
|
673
|
+
|
|
674
|
+
if (data === undefined) {
|
|
675
|
+
return null;
|
|
676
|
+
} else if (LiveObject.isJsonArray(data)) {
|
|
677
|
+
return LiveObject.compact(data.map(function (item) {
|
|
678
|
+
return parseServerMessage(item);
|
|
679
|
+
}));
|
|
680
|
+
} else {
|
|
681
|
+
return LiveObject.compact([parseServerMessage(data)]);
|
|
682
|
+
}
|
|
683
|
+
}
|
|
684
|
+
|
|
685
|
+
function onMessage(event) {
|
|
686
|
+
if (event.data === "pong") {
|
|
687
|
+
clearTimeout(state.timeoutHandles.pongTimeout);
|
|
688
|
+
return;
|
|
689
|
+
}
|
|
690
|
+
|
|
691
|
+
var messages = parseServerMessages(event.data);
|
|
692
|
+
|
|
693
|
+
if (messages === null || messages.length === 0) {
|
|
694
|
+
return;
|
|
695
|
+
}
|
|
696
|
+
|
|
697
|
+
var updates = {
|
|
698
|
+
storageUpdates: new Map(),
|
|
699
|
+
others: []
|
|
700
|
+
};
|
|
701
|
+
|
|
702
|
+
for (var _iterator9 = LiveObject._createForOfIteratorHelperLoose(messages), _step9; !(_step9 = _iterator9()).done;) {
|
|
703
|
+
var message = _step9.value;
|
|
704
|
+
|
|
705
|
+
switch (message.type) {
|
|
706
|
+
case LiveObject.ServerMessageType.UserJoined:
|
|
707
|
+
{
|
|
708
|
+
updates.others.push(onUserJoinedMessage(message));
|
|
709
|
+
break;
|
|
710
|
+
}
|
|
711
|
+
|
|
712
|
+
case LiveObject.ServerMessageType.UpdatePresence:
|
|
713
|
+
{
|
|
714
|
+
var othersPresenceUpdate = onUpdatePresenceMessage(message);
|
|
715
|
+
|
|
716
|
+
if (othersPresenceUpdate) {
|
|
717
|
+
updates.others.push(othersPresenceUpdate);
|
|
718
|
+
}
|
|
719
|
+
|
|
720
|
+
break;
|
|
721
|
+
}
|
|
722
|
+
|
|
723
|
+
case LiveObject.ServerMessageType.Event:
|
|
724
|
+
{
|
|
725
|
+
onEvent(message);
|
|
726
|
+
break;
|
|
727
|
+
}
|
|
728
|
+
|
|
729
|
+
case LiveObject.ServerMessageType.UserLeft:
|
|
730
|
+
{
|
|
731
|
+
var _event = onUserLeftMessage(message);
|
|
732
|
+
|
|
733
|
+
if (_event) {
|
|
734
|
+
updates.others.push(_event);
|
|
735
|
+
}
|
|
736
|
+
|
|
737
|
+
break;
|
|
738
|
+
}
|
|
739
|
+
|
|
740
|
+
case LiveObject.ServerMessageType.RoomState:
|
|
741
|
+
{
|
|
742
|
+
updates.others.push(onRoomStateMessage(message));
|
|
743
|
+
break;
|
|
744
|
+
}
|
|
745
|
+
|
|
746
|
+
case LiveObject.ServerMessageType.InitialStorageState:
|
|
747
|
+
{
|
|
748
|
+
var offlineOps = new Map(state.offlineOperations);
|
|
749
|
+
createOrUpdateRootFromMessage(message);
|
|
750
|
+
applyAndSendOfflineOps(offlineOps);
|
|
751
|
+
_getInitialStateResolver == null ? void 0 : _getInitialStateResolver();
|
|
752
|
+
break;
|
|
753
|
+
}
|
|
754
|
+
|
|
755
|
+
case LiveObject.ServerMessageType.UpdateStorage:
|
|
756
|
+
{
|
|
757
|
+
var applyResult = apply(message.ops, false);
|
|
758
|
+
applyResult.updates.storageUpdates.forEach(function (value, key) {
|
|
759
|
+
updates.storageUpdates.set(key, LiveObject.mergeStorageUpdates(updates.storageUpdates.get(key), value));
|
|
760
|
+
});
|
|
761
|
+
break;
|
|
762
|
+
}
|
|
763
|
+
}
|
|
764
|
+
}
|
|
765
|
+
|
|
766
|
+
notify(updates);
|
|
767
|
+
}
|
|
768
|
+
|
|
769
|
+
function onClose(event) {
|
|
770
|
+
state.socket = null;
|
|
771
|
+
clearTimeout(state.timeoutHandles.pongTimeout);
|
|
772
|
+
clearInterval(state.intervalHandles.heartbeat);
|
|
773
|
+
|
|
774
|
+
if (state.timeoutHandles.flush) {
|
|
775
|
+
clearTimeout(state.timeoutHandles.flush);
|
|
776
|
+
}
|
|
777
|
+
|
|
778
|
+
clearTimeout(state.timeoutHandles.reconnect);
|
|
779
|
+
state.users = {};
|
|
780
|
+
notify({
|
|
781
|
+
others: [{
|
|
782
|
+
type: "reset"
|
|
783
|
+
}]
|
|
784
|
+
});
|
|
785
|
+
|
|
786
|
+
if (event.code >= 4000 && event.code <= 4100) {
|
|
787
|
+
updateConnection({
|
|
788
|
+
state: "failed"
|
|
789
|
+
});
|
|
790
|
+
var error = new LiveblocksError(event.reason, event.code);
|
|
791
|
+
|
|
792
|
+
for (var _iterator10 = LiveObject._createForOfIteratorHelperLoose(state.listeners.error), _step10; !(_step10 = _iterator10()).done;) {
|
|
793
|
+
var _listener4 = _step10.value;
|
|
794
|
+
|
|
795
|
+
_listener4(error);
|
|
796
|
+
}
|
|
797
|
+
|
|
798
|
+
var _delay = getRetryDelay(true);
|
|
799
|
+
|
|
800
|
+
state.numberOfRetry++;
|
|
801
|
+
|
|
802
|
+
if (process.env.NODE_ENV !== "production") {
|
|
803
|
+
console.error("Connection to Liveblocks websocket server closed. Reason: " + error.message + " (code: " + error.code + "). Retrying in " + _delay + "ms.");
|
|
804
|
+
}
|
|
805
|
+
|
|
806
|
+
updateConnection({
|
|
807
|
+
state: "unavailable"
|
|
808
|
+
});
|
|
809
|
+
state.timeoutHandles.reconnect = effects.scheduleReconnect(_delay);
|
|
810
|
+
} else if (event.code === LiveObject.WebsocketCloseCodes.CLOSE_WITHOUT_RETRY) {
|
|
811
|
+
updateConnection({
|
|
812
|
+
state: "closed"
|
|
813
|
+
});
|
|
814
|
+
} else {
|
|
815
|
+
var _delay2 = getRetryDelay();
|
|
816
|
+
|
|
817
|
+
state.numberOfRetry++;
|
|
818
|
+
|
|
819
|
+
if (process.env.NODE_ENV !== "production") {
|
|
820
|
+
console.warn("Connection to Liveblocks websocket server closed (code: " + event.code + "). Retrying in " + _delay2 + "ms.");
|
|
821
|
+
}
|
|
822
|
+
|
|
823
|
+
updateConnection({
|
|
824
|
+
state: "unavailable"
|
|
825
|
+
});
|
|
826
|
+
state.timeoutHandles.reconnect = effects.scheduleReconnect(_delay2);
|
|
827
|
+
}
|
|
828
|
+
}
|
|
829
|
+
|
|
830
|
+
function updateConnection(connection) {
|
|
831
|
+
state.connection = connection;
|
|
832
|
+
|
|
833
|
+
for (var _iterator11 = LiveObject._createForOfIteratorHelperLoose(state.listeners.connection), _step11; !(_step11 = _iterator11()).done;) {
|
|
834
|
+
var _listener5 = _step11.value;
|
|
835
|
+
|
|
836
|
+
_listener5(connection.state);
|
|
837
|
+
}
|
|
838
|
+
}
|
|
839
|
+
|
|
840
|
+
function getRetryDelay(slow) {
|
|
841
|
+
if (slow === void 0) {
|
|
842
|
+
slow = false;
|
|
843
|
+
}
|
|
844
|
+
|
|
845
|
+
if (slow) {
|
|
846
|
+
return BACKOFF_RETRY_DELAYS_SLOW[state.numberOfRetry < BACKOFF_RETRY_DELAYS_SLOW.length ? state.numberOfRetry : BACKOFF_RETRY_DELAYS_SLOW.length - 1];
|
|
847
|
+
}
|
|
848
|
+
|
|
849
|
+
return BACKOFF_RETRY_DELAYS[state.numberOfRetry < BACKOFF_RETRY_DELAYS.length ? state.numberOfRetry : BACKOFF_RETRY_DELAYS.length - 1];
|
|
850
|
+
}
|
|
851
|
+
|
|
852
|
+
function onError() {}
|
|
853
|
+
|
|
854
|
+
function onOpen() {
|
|
855
|
+
clearInterval(state.intervalHandles.heartbeat);
|
|
856
|
+
state.intervalHandles.heartbeat = effects.startHeartbeatInterval();
|
|
857
|
+
|
|
858
|
+
if (state.connection.state === "connecting") {
|
|
859
|
+
updateConnection(LiveObject._extends({}, state.connection, {
|
|
860
|
+
state: "open"
|
|
861
|
+
}));
|
|
862
|
+
state.numberOfRetry = 0;
|
|
863
|
+
|
|
864
|
+
if (state.lastConnectionId !== undefined) {
|
|
865
|
+
state.buffer.presence = state.me;
|
|
866
|
+
tryFlushing();
|
|
867
|
+
}
|
|
868
|
+
|
|
869
|
+
state.lastConnectionId = state.connection.id;
|
|
870
|
+
|
|
871
|
+
if (state.root) {
|
|
872
|
+
state.buffer.messages.push({
|
|
873
|
+
type: LiveObject.ClientMessageType.FetchStorage
|
|
874
|
+
});
|
|
875
|
+
}
|
|
876
|
+
|
|
877
|
+
tryFlushing();
|
|
878
|
+
}
|
|
879
|
+
}
|
|
880
|
+
|
|
881
|
+
function heartbeat() {
|
|
882
|
+
if (state.socket == null) {
|
|
883
|
+
return;
|
|
884
|
+
}
|
|
885
|
+
|
|
886
|
+
clearTimeout(state.timeoutHandles.pongTimeout);
|
|
887
|
+
state.timeoutHandles.pongTimeout = effects.schedulePongTimeout();
|
|
888
|
+
|
|
889
|
+
if (state.socket.readyState === state.socket.OPEN) {
|
|
890
|
+
state.socket.send("ping");
|
|
891
|
+
}
|
|
892
|
+
}
|
|
893
|
+
|
|
894
|
+
function pongTimeout() {
|
|
895
|
+
reconnect();
|
|
896
|
+
}
|
|
897
|
+
|
|
898
|
+
function reconnect() {
|
|
899
|
+
if (state.socket) {
|
|
900
|
+
state.socket.removeEventListener("open", onOpen);
|
|
901
|
+
state.socket.removeEventListener("message", onMessage);
|
|
902
|
+
state.socket.removeEventListener("close", onClose);
|
|
903
|
+
state.socket.removeEventListener("error", onError);
|
|
904
|
+
state.socket.close();
|
|
905
|
+
state.socket = null;
|
|
906
|
+
}
|
|
907
|
+
|
|
908
|
+
updateConnection({
|
|
909
|
+
state: "unavailable"
|
|
910
|
+
});
|
|
911
|
+
clearTimeout(state.timeoutHandles.pongTimeout);
|
|
912
|
+
|
|
913
|
+
if (state.timeoutHandles.flush) {
|
|
914
|
+
clearTimeout(state.timeoutHandles.flush);
|
|
915
|
+
}
|
|
916
|
+
|
|
917
|
+
clearTimeout(state.timeoutHandles.reconnect);
|
|
918
|
+
clearInterval(state.intervalHandles.heartbeat);
|
|
919
|
+
connect();
|
|
920
|
+
}
|
|
921
|
+
|
|
922
|
+
function applyAndSendOfflineOps(offlineOps) {
|
|
923
|
+
if (offlineOps.size === 0) {
|
|
924
|
+
return;
|
|
925
|
+
}
|
|
926
|
+
|
|
927
|
+
var messages = [];
|
|
928
|
+
var ops = Array.from(offlineOps.values());
|
|
929
|
+
var result = apply(ops, true);
|
|
930
|
+
messages.push({
|
|
931
|
+
type: LiveObject.ClientMessageType.UpdateStorage,
|
|
932
|
+
ops: ops
|
|
933
|
+
});
|
|
934
|
+
notify(result.updates);
|
|
935
|
+
effects.send(messages);
|
|
936
|
+
}
|
|
937
|
+
|
|
938
|
+
function tryFlushing() {
|
|
939
|
+
var storageOps = state.buffer.storageOperations;
|
|
940
|
+
|
|
941
|
+
if (storageOps.length > 0) {
|
|
942
|
+
storageOps.forEach(function (op) {
|
|
943
|
+
state.offlineOperations.set(op.opId, op);
|
|
944
|
+
});
|
|
945
|
+
}
|
|
946
|
+
|
|
947
|
+
if (state.socket == null || state.socket.readyState !== state.socket.OPEN) {
|
|
948
|
+
state.buffer.storageOperations = [];
|
|
949
|
+
return;
|
|
950
|
+
}
|
|
951
|
+
|
|
952
|
+
var now = Date.now();
|
|
953
|
+
var elapsedTime = now - state.lastFlushTime;
|
|
954
|
+
|
|
955
|
+
if (elapsedTime > context.throttleDelay) {
|
|
956
|
+
var _messages = flushDataToMessages(state);
|
|
957
|
+
|
|
958
|
+
if (_messages.length === 0) {
|
|
959
|
+
return;
|
|
960
|
+
}
|
|
961
|
+
|
|
962
|
+
effects.send(_messages);
|
|
963
|
+
state.buffer = {
|
|
964
|
+
messages: [],
|
|
965
|
+
storageOperations: [],
|
|
966
|
+
presence: null
|
|
967
|
+
};
|
|
968
|
+
state.lastFlushTime = now;
|
|
969
|
+
} else {
|
|
970
|
+
if (state.timeoutHandles.flush != null) {
|
|
971
|
+
clearTimeout(state.timeoutHandles.flush);
|
|
972
|
+
}
|
|
973
|
+
|
|
974
|
+
state.timeoutHandles.flush = effects.delayFlush(context.throttleDelay - (now - state.lastFlushTime));
|
|
975
|
+
}
|
|
976
|
+
}
|
|
977
|
+
|
|
978
|
+
function flushDataToMessages(state) {
|
|
979
|
+
var messages = [];
|
|
980
|
+
|
|
981
|
+
if (state.buffer.presence) {
|
|
982
|
+
messages.push({
|
|
983
|
+
type: LiveObject.ClientMessageType.UpdatePresence,
|
|
984
|
+
data: state.buffer.presence
|
|
985
|
+
});
|
|
986
|
+
}
|
|
987
|
+
|
|
988
|
+
for (var _iterator12 = LiveObject._createForOfIteratorHelperLoose(state.buffer.messages), _step12; !(_step12 = _iterator12()).done;) {
|
|
989
|
+
var event = _step12.value;
|
|
990
|
+
messages.push(event);
|
|
991
|
+
}
|
|
992
|
+
|
|
993
|
+
if (state.buffer.storageOperations.length > 0) {
|
|
994
|
+
messages.push({
|
|
995
|
+
type: LiveObject.ClientMessageType.UpdateStorage,
|
|
996
|
+
ops: state.buffer.storageOperations
|
|
997
|
+
});
|
|
998
|
+
}
|
|
999
|
+
|
|
1000
|
+
return messages;
|
|
1001
|
+
}
|
|
1002
|
+
|
|
1003
|
+
function disconnect() {
|
|
1004
|
+
if (state.socket) {
|
|
1005
|
+
state.socket.removeEventListener("open", onOpen);
|
|
1006
|
+
state.socket.removeEventListener("message", onMessage);
|
|
1007
|
+
state.socket.removeEventListener("close", onClose);
|
|
1008
|
+
state.socket.removeEventListener("error", onError);
|
|
1009
|
+
state.socket.close();
|
|
1010
|
+
state.socket = null;
|
|
1011
|
+
}
|
|
1012
|
+
|
|
1013
|
+
updateConnection({
|
|
1014
|
+
state: "closed"
|
|
1015
|
+
});
|
|
1016
|
+
|
|
1017
|
+
if (state.timeoutHandles.flush) {
|
|
1018
|
+
clearTimeout(state.timeoutHandles.flush);
|
|
1019
|
+
}
|
|
1020
|
+
|
|
1021
|
+
clearTimeout(state.timeoutHandles.reconnect);
|
|
1022
|
+
clearTimeout(state.timeoutHandles.pongTimeout);
|
|
1023
|
+
clearInterval(state.intervalHandles.heartbeat);
|
|
1024
|
+
state.users = {};
|
|
1025
|
+
notify({
|
|
1026
|
+
others: [{
|
|
1027
|
+
type: "reset"
|
|
1028
|
+
}]
|
|
1029
|
+
});
|
|
1030
|
+
clearListeners();
|
|
1031
|
+
}
|
|
1032
|
+
|
|
1033
|
+
function clearListeners() {
|
|
1034
|
+
for (var _key6 in state.listeners) {
|
|
1035
|
+
state.listeners[_key6] = [];
|
|
1036
|
+
}
|
|
1037
|
+
}
|
|
1038
|
+
|
|
1039
|
+
function getPresence() {
|
|
1040
|
+
return state.me;
|
|
1041
|
+
}
|
|
1042
|
+
|
|
1043
|
+
function getOthers() {
|
|
1044
|
+
return state.others;
|
|
1045
|
+
}
|
|
1046
|
+
|
|
1047
|
+
function broadcastEvent(event, options) {
|
|
1048
|
+
if (options === void 0) {
|
|
1049
|
+
options = {
|
|
1050
|
+
shouldQueueEventIfNotReady: false
|
|
1051
|
+
};
|
|
1052
|
+
}
|
|
1053
|
+
|
|
1054
|
+
if (state.socket == null && options.shouldQueueEventIfNotReady == false) {
|
|
1055
|
+
return;
|
|
1056
|
+
}
|
|
1057
|
+
|
|
1058
|
+
state.buffer.messages.push({
|
|
1059
|
+
type: LiveObject.ClientMessageType.ClientEvent,
|
|
1060
|
+
event: event
|
|
1061
|
+
});
|
|
1062
|
+
tryFlushing();
|
|
1063
|
+
}
|
|
1064
|
+
|
|
1065
|
+
function dispatch(ops) {
|
|
1066
|
+
var _state$buffer$storage;
|
|
1067
|
+
|
|
1068
|
+
(_state$buffer$storage = state.buffer.storageOperations).push.apply(_state$buffer$storage, ops);
|
|
1069
|
+
|
|
1070
|
+
tryFlushing();
|
|
1071
|
+
}
|
|
1072
|
+
|
|
1073
|
+
var _getInitialStatePromise = null;
|
|
1074
|
+
var _getInitialStateResolver = null;
|
|
1075
|
+
|
|
1076
|
+
function getStorage() {
|
|
1077
|
+
if (state.root) {
|
|
1078
|
+
return new Promise(function (resolve) {
|
|
1079
|
+
return resolve({
|
|
1080
|
+
root: state.root
|
|
1081
|
+
});
|
|
1082
|
+
});
|
|
1083
|
+
}
|
|
1084
|
+
|
|
1085
|
+
if (_getInitialStatePromise == null) {
|
|
1086
|
+
state.buffer.messages.push({
|
|
1087
|
+
type: LiveObject.ClientMessageType.FetchStorage
|
|
1088
|
+
});
|
|
1089
|
+
tryFlushing();
|
|
1090
|
+
_getInitialStatePromise = new Promise(function (resolve) {
|
|
1091
|
+
return _getInitialStateResolver = resolve;
|
|
1092
|
+
});
|
|
1093
|
+
}
|
|
1094
|
+
|
|
1095
|
+
return _getInitialStatePromise.then(function () {
|
|
1096
|
+
return {
|
|
1097
|
+
root: state.root
|
|
1098
|
+
};
|
|
1099
|
+
});
|
|
1100
|
+
}
|
|
1101
|
+
|
|
1102
|
+
function undo() {
|
|
1103
|
+
if (state.isBatching) {
|
|
1104
|
+
throw new Error("undo is not allowed during a batch");
|
|
1105
|
+
}
|
|
1106
|
+
|
|
1107
|
+
var historyItem = state.undoStack.pop();
|
|
1108
|
+
|
|
1109
|
+
if (historyItem == null) {
|
|
1110
|
+
return;
|
|
1111
|
+
}
|
|
1112
|
+
|
|
1113
|
+
state.isHistoryPaused = false;
|
|
1114
|
+
var result = apply(historyItem, true);
|
|
1115
|
+
notify(result.updates);
|
|
1116
|
+
state.redoStack.push(result.reverse);
|
|
1117
|
+
|
|
1118
|
+
for (var _iterator13 = LiveObject._createForOfIteratorHelperLoose(historyItem), _step13; !(_step13 = _iterator13()).done;) {
|
|
1119
|
+
var op = _step13.value;
|
|
1120
|
+
|
|
1121
|
+
if (op.type !== "presence") {
|
|
1122
|
+
state.buffer.storageOperations.push(op);
|
|
1123
|
+
}
|
|
1124
|
+
}
|
|
1125
|
+
|
|
1126
|
+
tryFlushing();
|
|
1127
|
+
}
|
|
1128
|
+
|
|
1129
|
+
function redo() {
|
|
1130
|
+
if (state.isBatching) {
|
|
1131
|
+
throw new Error("redo is not allowed during a batch");
|
|
1132
|
+
}
|
|
1133
|
+
|
|
1134
|
+
var historyItem = state.redoStack.pop();
|
|
1135
|
+
|
|
1136
|
+
if (historyItem == null) {
|
|
1137
|
+
return;
|
|
1138
|
+
}
|
|
1139
|
+
|
|
1140
|
+
state.isHistoryPaused = false;
|
|
1141
|
+
var result = apply(historyItem, true);
|
|
1142
|
+
notify(result.updates);
|
|
1143
|
+
state.undoStack.push(result.reverse);
|
|
1144
|
+
|
|
1145
|
+
for (var _iterator14 = LiveObject._createForOfIteratorHelperLoose(historyItem), _step14; !(_step14 = _iterator14()).done;) {
|
|
1146
|
+
var op = _step14.value;
|
|
1147
|
+
|
|
1148
|
+
if (op.type !== "presence") {
|
|
1149
|
+
state.buffer.storageOperations.push(op);
|
|
1150
|
+
}
|
|
1151
|
+
}
|
|
1152
|
+
|
|
1153
|
+
tryFlushing();
|
|
1154
|
+
}
|
|
1155
|
+
|
|
1156
|
+
function batch(callback) {
|
|
1157
|
+
if (state.isBatching) {
|
|
1158
|
+
throw new Error("batch should not be called during a batch");
|
|
1159
|
+
}
|
|
1160
|
+
|
|
1161
|
+
state.isBatching = true;
|
|
1162
|
+
|
|
1163
|
+
try {
|
|
1164
|
+
callback();
|
|
1165
|
+
} finally {
|
|
1166
|
+
state.isBatching = false;
|
|
1167
|
+
|
|
1168
|
+
if (state.batch.reverseOps.length > 0) {
|
|
1169
|
+
addToUndoStack(state.batch.reverseOps);
|
|
1170
|
+
}
|
|
1171
|
+
|
|
1172
|
+
if (state.batch.ops.length > 0) {
|
|
1173
|
+
state.redoStack = [];
|
|
1174
|
+
}
|
|
1175
|
+
|
|
1176
|
+
if (state.batch.ops.length > 0) {
|
|
1177
|
+
dispatch(state.batch.ops);
|
|
1178
|
+
}
|
|
1179
|
+
|
|
1180
|
+
notify(state.batch.updates);
|
|
1181
|
+
state.batch = {
|
|
1182
|
+
ops: [],
|
|
1183
|
+
reverseOps: [],
|
|
1184
|
+
updates: {
|
|
1185
|
+
others: [],
|
|
1186
|
+
storageUpdates: new Map(),
|
|
1187
|
+
presence: false
|
|
1188
|
+
}
|
|
1189
|
+
};
|
|
1190
|
+
tryFlushing();
|
|
1191
|
+
}
|
|
1192
|
+
}
|
|
1193
|
+
|
|
1194
|
+
function pauseHistory() {
|
|
1195
|
+
state.pausedHistory = [];
|
|
1196
|
+
state.isHistoryPaused = true;
|
|
1197
|
+
}
|
|
1198
|
+
|
|
1199
|
+
function resumeHistory() {
|
|
1200
|
+
state.isHistoryPaused = false;
|
|
1201
|
+
|
|
1202
|
+
if (state.pausedHistory.length > 0) {
|
|
1203
|
+
addToUndoStack(state.pausedHistory);
|
|
1204
|
+
}
|
|
1205
|
+
|
|
1206
|
+
state.pausedHistory = [];
|
|
1207
|
+
}
|
|
1208
|
+
|
|
1209
|
+
function simulateSocketClose() {
|
|
1210
|
+
if (state.socket) {
|
|
1211
|
+
state.socket.close();
|
|
1212
|
+
}
|
|
1213
|
+
}
|
|
1214
|
+
|
|
1215
|
+
function simulateSendCloseEvent(event) {
|
|
1216
|
+
if (state.socket) {
|
|
1217
|
+
onClose(event);
|
|
1218
|
+
}
|
|
1219
|
+
}
|
|
1220
|
+
|
|
1221
|
+
return {
|
|
1222
|
+
onClose: onClose,
|
|
1223
|
+
onMessage: onMessage,
|
|
1224
|
+
authenticationSuccess: authenticationSuccess,
|
|
1225
|
+
heartbeat: heartbeat,
|
|
1226
|
+
onNavigatorOnline: onNavigatorOnline,
|
|
1227
|
+
simulateSocketClose: simulateSocketClose,
|
|
1228
|
+
simulateSendCloseEvent: simulateSendCloseEvent,
|
|
1229
|
+
onVisibilityChange: onVisibilityChange,
|
|
1230
|
+
getUndoStack: function getUndoStack() {
|
|
1231
|
+
return state.undoStack;
|
|
1232
|
+
},
|
|
1233
|
+
getItemsCount: function getItemsCount() {
|
|
1234
|
+
return state.items.size;
|
|
1235
|
+
},
|
|
1236
|
+
connect: connect,
|
|
1237
|
+
disconnect: disconnect,
|
|
1238
|
+
subscribe: subscribe,
|
|
1239
|
+
unsubscribe: unsubscribe,
|
|
1240
|
+
updatePresence: updatePresence,
|
|
1241
|
+
broadcastEvent: broadcastEvent,
|
|
1242
|
+
batch: batch,
|
|
1243
|
+
undo: undo,
|
|
1244
|
+
redo: redo,
|
|
1245
|
+
pauseHistory: pauseHistory,
|
|
1246
|
+
resumeHistory: resumeHistory,
|
|
1247
|
+
getStorage: getStorage,
|
|
1248
|
+
selectors: {
|
|
1249
|
+
getConnectionState: getConnectionState,
|
|
1250
|
+
getSelf: getSelf,
|
|
1251
|
+
getPresence: getPresence,
|
|
1252
|
+
getOthers: getOthers
|
|
1253
|
+
}
|
|
1254
|
+
};
|
|
1255
|
+
}
|
|
1256
|
+
function defaultState(me, defaultStorageRoot) {
|
|
1257
|
+
return {
|
|
1258
|
+
connection: {
|
|
1259
|
+
state: "closed"
|
|
1260
|
+
},
|
|
1261
|
+
token: null,
|
|
1262
|
+
lastConnectionId: null,
|
|
1263
|
+
socket: null,
|
|
1264
|
+
listeners: {
|
|
1265
|
+
event: [],
|
|
1266
|
+
others: [],
|
|
1267
|
+
"my-presence": [],
|
|
1268
|
+
error: [],
|
|
1269
|
+
connection: [],
|
|
1270
|
+
storage: []
|
|
1271
|
+
},
|
|
1272
|
+
numberOfRetry: 0,
|
|
1273
|
+
lastFlushTime: 0,
|
|
1274
|
+
timeoutHandles: {
|
|
1275
|
+
flush: null,
|
|
1276
|
+
reconnect: 0,
|
|
1277
|
+
pongTimeout: 0
|
|
1278
|
+
},
|
|
1279
|
+
buffer: {
|
|
1280
|
+
presence: me == null ? {} : me,
|
|
1281
|
+
messages: [],
|
|
1282
|
+
storageOperations: []
|
|
1283
|
+
},
|
|
1284
|
+
intervalHandles: {
|
|
1285
|
+
heartbeat: 0
|
|
1286
|
+
},
|
|
1287
|
+
me: me == null ? {} : me,
|
|
1288
|
+
users: {},
|
|
1289
|
+
others: makeOthers({}),
|
|
1290
|
+
defaultStorageRoot: defaultStorageRoot,
|
|
1291
|
+
idFactory: null,
|
|
1292
|
+
clock: 0,
|
|
1293
|
+
opClock: 0,
|
|
1294
|
+
items: new Map(),
|
|
1295
|
+
root: undefined,
|
|
1296
|
+
undoStack: [],
|
|
1297
|
+
redoStack: [],
|
|
1298
|
+
isHistoryPaused: false,
|
|
1299
|
+
pausedHistory: [],
|
|
1300
|
+
isBatching: false,
|
|
1301
|
+
batch: {
|
|
1302
|
+
ops: [],
|
|
1303
|
+
updates: {
|
|
1304
|
+
storageUpdates: new Map(),
|
|
1305
|
+
presence: false,
|
|
1306
|
+
others: []
|
|
1307
|
+
},
|
|
1308
|
+
reverseOps: []
|
|
1309
|
+
},
|
|
1310
|
+
offlineOperations: new Map()
|
|
1311
|
+
};
|
|
1312
|
+
}
|
|
1313
|
+
function createRoom(options, context) {
|
|
1314
|
+
var state = defaultState(options.defaultPresence, options.defaultStorageRoot);
|
|
1315
|
+
var machine = makeStateMachine(state, context);
|
|
1316
|
+
var room = {
|
|
1317
|
+
id: context.roomId,
|
|
1318
|
+
getConnectionState: machine.selectors.getConnectionState,
|
|
1319
|
+
getSelf: machine.selectors.getSelf,
|
|
1320
|
+
subscribe: machine.subscribe,
|
|
1321
|
+
unsubscribe: machine.unsubscribe,
|
|
1322
|
+
getPresence: machine.selectors.getPresence,
|
|
1323
|
+
updatePresence: machine.updatePresence,
|
|
1324
|
+
getOthers: machine.selectors.getOthers,
|
|
1325
|
+
broadcastEvent: machine.broadcastEvent,
|
|
1326
|
+
getStorage: machine.getStorage,
|
|
1327
|
+
batch: machine.batch,
|
|
1328
|
+
history: {
|
|
1329
|
+
undo: machine.undo,
|
|
1330
|
+
redo: machine.redo,
|
|
1331
|
+
pause: machine.pauseHistory,
|
|
1332
|
+
resume: machine.resumeHistory
|
|
1333
|
+
},
|
|
1334
|
+
internalDevTools: {
|
|
1335
|
+
closeWebsocket: machine.simulateSocketClose,
|
|
1336
|
+
sendCloseEvent: machine.simulateSendCloseEvent
|
|
1337
|
+
}
|
|
1338
|
+
};
|
|
1339
|
+
return {
|
|
1340
|
+
connect: machine.connect,
|
|
1341
|
+
disconnect: machine.disconnect,
|
|
1342
|
+
onNavigatorOnline: machine.onNavigatorOnline,
|
|
1343
|
+
onVisibilityChange: machine.onVisibilityChange,
|
|
1344
|
+
room: room
|
|
1345
|
+
};
|
|
1346
|
+
}
|
|
1347
|
+
|
|
1348
|
+
var LiveblocksError = function (_Error) {
|
|
1349
|
+
LiveObject._inheritsLoose(LiveblocksError, _Error);
|
|
1350
|
+
|
|
1351
|
+
function LiveblocksError(message, code) {
|
|
1352
|
+
var _this;
|
|
1353
|
+
|
|
1354
|
+
_this = _Error.call(this, message) || this;
|
|
1355
|
+
_this.code = code;
|
|
1356
|
+
return _this;
|
|
1357
|
+
}
|
|
1358
|
+
|
|
1359
|
+
return LiveblocksError;
|
|
1360
|
+
}(LiveObject._wrapNativeSuper(Error));
|
|
1361
|
+
|
|
1362
|
+
function parseToken(token) {
|
|
1363
|
+
var tokenParts = token.split(".");
|
|
1364
|
+
|
|
1365
|
+
if (tokenParts.length !== 3) {
|
|
1366
|
+
throw new Error("Authentication error. Liveblocks could not parse the response of your authentication endpoint");
|
|
1367
|
+
}
|
|
1368
|
+
|
|
1369
|
+
var data = LiveObject.parseJson(atob(tokenParts[1]));
|
|
1370
|
+
|
|
1371
|
+
if (data !== undefined && LiveObject.isJsonObject(data) && typeof data.actor === "number" && (data.id === undefined || typeof data.id === "string")) {
|
|
1372
|
+
return {
|
|
1373
|
+
actor: data.actor,
|
|
1374
|
+
id: data.id,
|
|
1375
|
+
info: data.info
|
|
1376
|
+
};
|
|
1377
|
+
}
|
|
1378
|
+
|
|
1379
|
+
throw new Error("Authentication error. Liveblocks could not parse the response of your authentication endpoint");
|
|
1380
|
+
}
|
|
1381
|
+
|
|
1382
|
+
function prepareCreateWebSocket(liveblocksServer, WebSocketPolyfill) {
|
|
1383
|
+
if (typeof window === "undefined" && WebSocketPolyfill == null) {
|
|
1384
|
+
throw new Error("To use Liveblocks client in a non-dom environment, you need to provide a WebSocket polyfill.");
|
|
1385
|
+
}
|
|
1386
|
+
|
|
1387
|
+
var ws = WebSocketPolyfill || WebSocket;
|
|
1388
|
+
return function (token) {
|
|
1389
|
+
return new ws(liveblocksServer + "/?token=" + token);
|
|
1390
|
+
};
|
|
1391
|
+
}
|
|
1392
|
+
|
|
1393
|
+
function prepareAuthEndpoint(authentication, fetchPolyfill) {
|
|
1394
|
+
if (authentication.type === "public") {
|
|
1395
|
+
if (typeof window === "undefined" && fetchPolyfill == null) {
|
|
1396
|
+
throw new Error("To use Liveblocks client in a non-dom environment with a publicApiKey, you need to provide a fetch polyfill.");
|
|
1397
|
+
}
|
|
1398
|
+
|
|
1399
|
+
return function (room) {
|
|
1400
|
+
return fetchAuthEndpoint(fetchPolyfill || fetch, authentication.url, {
|
|
1401
|
+
room: room,
|
|
1402
|
+
publicApiKey: authentication.publicApiKey
|
|
1403
|
+
});
|
|
1404
|
+
};
|
|
1405
|
+
}
|
|
1406
|
+
|
|
1407
|
+
if (authentication.type === "private") {
|
|
1408
|
+
if (typeof window === "undefined" && fetchPolyfill == null) {
|
|
1409
|
+
throw new Error("To use Liveblocks client in a non-dom environment with a url as auth endpoint, you need to provide a fetch polyfill.");
|
|
1410
|
+
}
|
|
1411
|
+
|
|
1412
|
+
return function (room) {
|
|
1413
|
+
return fetchAuthEndpoint(fetchPolyfill || fetch, authentication.url, {
|
|
1414
|
+
room: room
|
|
1415
|
+
});
|
|
1416
|
+
};
|
|
1417
|
+
}
|
|
1418
|
+
|
|
1419
|
+
if (authentication.type === "custom") {
|
|
1420
|
+
return authentication.callback;
|
|
1421
|
+
}
|
|
1422
|
+
|
|
1423
|
+
throw new Error("Internal error. Unexpected authentication type");
|
|
1424
|
+
}
|
|
1425
|
+
|
|
1426
|
+
function fetchAuthEndpoint(fetch, endpoint, body) {
|
|
1427
|
+
return fetch(endpoint, {
|
|
1428
|
+
method: "POST",
|
|
1429
|
+
headers: {
|
|
1430
|
+
"Content-Type": "application/json"
|
|
1431
|
+
},
|
|
1432
|
+
body: JSON.stringify(body)
|
|
1433
|
+
}).then(function (res) {
|
|
1434
|
+
if (!res.ok) {
|
|
1435
|
+
throw new AuthenticationError("Expected a status 200 but got " + res.status + " when doing a POST request on \"" + endpoint + "\"");
|
|
1436
|
+
}
|
|
1437
|
+
|
|
1438
|
+
return res.json().catch(function (er) {
|
|
1439
|
+
throw new AuthenticationError("Expected a json when doing a POST request on \"" + endpoint + "\". " + er);
|
|
1440
|
+
});
|
|
1441
|
+
}).then(function (authResponse) {
|
|
1442
|
+
if (typeof authResponse.token !== "string") {
|
|
1443
|
+
throw new AuthenticationError("Expected a json with a string token when doing a POST request on \"" + endpoint + "\", but got " + JSON.stringify(authResponse));
|
|
1444
|
+
}
|
|
1445
|
+
|
|
1446
|
+
return authResponse;
|
|
1447
|
+
});
|
|
1448
|
+
}
|
|
1449
|
+
|
|
1450
|
+
var AuthenticationError = function (_Error2) {
|
|
1451
|
+
LiveObject._inheritsLoose(AuthenticationError, _Error2);
|
|
1452
|
+
|
|
1453
|
+
function AuthenticationError(message) {
|
|
1454
|
+
return _Error2.call(this, message) || this;
|
|
1455
|
+
}
|
|
1456
|
+
|
|
1457
|
+
return AuthenticationError;
|
|
1458
|
+
}(LiveObject._wrapNativeSuper(Error));
|
|
1459
|
+
|
|
1460
|
+
function createClient(options) {
|
|
1461
|
+
var clientOptions = options;
|
|
1462
|
+
var throttleDelay = getThrottleDelayFromOptions(options);
|
|
1463
|
+
var rooms = new Map();
|
|
1464
|
+
|
|
1465
|
+
function getRoom(roomId) {
|
|
1466
|
+
var internalRoom = rooms.get(roomId);
|
|
1467
|
+
return internalRoom ? internalRoom.room : null;
|
|
1468
|
+
}
|
|
1469
|
+
|
|
1470
|
+
function enter(roomId, options) {
|
|
1471
|
+
if (options === void 0) {
|
|
1472
|
+
options = {};
|
|
1473
|
+
}
|
|
1474
|
+
|
|
1475
|
+
var internalRoom = rooms.get(roomId);
|
|
1476
|
+
|
|
1477
|
+
if (internalRoom) {
|
|
1478
|
+
return internalRoom.room;
|
|
1479
|
+
}
|
|
1480
|
+
|
|
1481
|
+
internalRoom = createRoom({
|
|
1482
|
+
defaultPresence: options.defaultPresence,
|
|
1483
|
+
defaultStorageRoot: options.defaultStorageRoot
|
|
1484
|
+
}, {
|
|
1485
|
+
roomId: roomId,
|
|
1486
|
+
throttleDelay: throttleDelay,
|
|
1487
|
+
WebSocketPolyfill: clientOptions.WebSocketPolyfill,
|
|
1488
|
+
fetchPolyfill: clientOptions.fetchPolyfill,
|
|
1489
|
+
liveblocksServer: clientOptions.liveblocksServer || "wss://liveblocks.net/v5",
|
|
1490
|
+
authentication: prepareAuthentication(clientOptions)
|
|
1491
|
+
});
|
|
1492
|
+
rooms.set(roomId, internalRoom);
|
|
1493
|
+
|
|
1494
|
+
if (!options.DO_NOT_USE_withoutConnecting) {
|
|
1495
|
+
internalRoom.connect();
|
|
1496
|
+
}
|
|
1497
|
+
|
|
1498
|
+
return internalRoom.room;
|
|
1499
|
+
}
|
|
1500
|
+
|
|
1501
|
+
function leave(roomId) {
|
|
1502
|
+
var room = rooms.get(roomId);
|
|
1503
|
+
|
|
1504
|
+
if (room) {
|
|
1505
|
+
room.disconnect();
|
|
1506
|
+
rooms.delete(roomId);
|
|
1507
|
+
}
|
|
1508
|
+
}
|
|
1509
|
+
|
|
1510
|
+
if (typeof window !== "undefined") {
|
|
1511
|
+
window.addEventListener("online", function () {
|
|
1512
|
+
for (var _iterator = LiveObject._createForOfIteratorHelperLoose(rooms), _step; !(_step = _iterator()).done;) {
|
|
1513
|
+
var _step$value = _step.value,
|
|
1514
|
+
room = _step$value[1];
|
|
1515
|
+
room.onNavigatorOnline();
|
|
1516
|
+
}
|
|
1517
|
+
});
|
|
1518
|
+
}
|
|
1519
|
+
|
|
1520
|
+
if (typeof document !== "undefined") {
|
|
1521
|
+
document.addEventListener("visibilitychange", function () {
|
|
1522
|
+
for (var _iterator2 = LiveObject._createForOfIteratorHelperLoose(rooms), _step2; !(_step2 = _iterator2()).done;) {
|
|
1523
|
+
var _step2$value = _step2.value,
|
|
1524
|
+
room = _step2$value[1];
|
|
1525
|
+
room.onVisibilityChange(document.visibilityState);
|
|
1526
|
+
}
|
|
1527
|
+
});
|
|
1528
|
+
}
|
|
1529
|
+
|
|
1530
|
+
return {
|
|
1531
|
+
getRoom: getRoom,
|
|
1532
|
+
enter: enter,
|
|
1533
|
+
leave: leave
|
|
1534
|
+
};
|
|
1535
|
+
}
|
|
1536
|
+
|
|
1537
|
+
function getThrottleDelayFromOptions(options) {
|
|
1538
|
+
if (options.throttle === undefined) {
|
|
1539
|
+
return 100;
|
|
1540
|
+
}
|
|
1541
|
+
|
|
1542
|
+
if (typeof options.throttle !== "number" || options.throttle < 80 || options.throttle > 1000) {
|
|
1543
|
+
throw new Error("throttle should be a number between 80 and 1000.");
|
|
1544
|
+
}
|
|
1545
|
+
|
|
1546
|
+
return options.throttle;
|
|
1547
|
+
}
|
|
1548
|
+
|
|
1549
|
+
function prepareAuthentication(clientOptions) {
|
|
1550
|
+
if (typeof clientOptions.publicApiKey === "string") {
|
|
1551
|
+
return {
|
|
1552
|
+
type: "public",
|
|
1553
|
+
publicApiKey: clientOptions.publicApiKey,
|
|
1554
|
+
url: clientOptions.publicAuthorizeEndpoint || "https://liveblocks.io/api/public/authorize"
|
|
1555
|
+
};
|
|
1556
|
+
} else if (typeof clientOptions.authEndpoint === "string") {
|
|
1557
|
+
return {
|
|
1558
|
+
type: "private",
|
|
1559
|
+
url: clientOptions.authEndpoint
|
|
1560
|
+
};
|
|
1561
|
+
} else if (typeof clientOptions.authEndpoint === "function") {
|
|
1562
|
+
return {
|
|
1563
|
+
type: "custom",
|
|
1564
|
+
callback: clientOptions.authEndpoint
|
|
1565
|
+
};
|
|
1566
|
+
}
|
|
1567
|
+
|
|
1568
|
+
throw new Error("Invalid Liveblocks client options. For more information: https://liveblocks.io/docs/api-reference/liveblocks-client#createClient");
|
|
1569
|
+
}
|
|
1570
|
+
|
|
1571
|
+
function lsonObjectToJson(obj) {
|
|
1572
|
+
var result = {};
|
|
1573
|
+
|
|
1574
|
+
for (var _key in obj) {
|
|
1575
|
+
var val = obj[_key];
|
|
1576
|
+
|
|
1577
|
+
if (val !== undefined) {
|
|
1578
|
+
result[_key] = lsonToJson(val);
|
|
1579
|
+
}
|
|
1580
|
+
}
|
|
1581
|
+
|
|
1582
|
+
return result;
|
|
1583
|
+
}
|
|
1584
|
+
|
|
1585
|
+
function liveObjectToJson(liveObject) {
|
|
1586
|
+
return lsonObjectToJson(liveObject.toObject());
|
|
1587
|
+
}
|
|
1588
|
+
|
|
1589
|
+
function liveMapToJson(map) {
|
|
1590
|
+
var result = {};
|
|
1591
|
+
|
|
1592
|
+
for (var _iterator = LiveObject._createForOfIteratorHelperLoose(map.entries()), _step; !(_step = _iterator()).done;) {
|
|
1593
|
+
var _step$value = _step.value,
|
|
1594
|
+
_key2 = _step$value[0],
|
|
1595
|
+
value = _step$value[1];
|
|
1596
|
+
result[_key2] = lsonToJson(value);
|
|
1597
|
+
}
|
|
1598
|
+
|
|
1599
|
+
return result;
|
|
1600
|
+
}
|
|
1601
|
+
|
|
1602
|
+
function lsonListToJson(value) {
|
|
1603
|
+
return value.map(lsonToJson);
|
|
1604
|
+
}
|
|
1605
|
+
|
|
1606
|
+
function liveListToJson(value) {
|
|
1607
|
+
return lsonListToJson(value.toArray());
|
|
1608
|
+
}
|
|
1609
|
+
|
|
1610
|
+
function lsonToJson(value) {
|
|
1611
|
+
if (value instanceof LiveObject.LiveObject) {
|
|
1612
|
+
return liveObjectToJson(value);
|
|
1613
|
+
} else if (value instanceof LiveObject.LiveList) {
|
|
1614
|
+
return liveListToJson(value);
|
|
1615
|
+
} else if (value instanceof LiveObject.LiveMap) {
|
|
1616
|
+
return liveMapToJson(value);
|
|
1617
|
+
} else if (value instanceof LiveObject.LiveRegister) {
|
|
1618
|
+
return value.data;
|
|
1619
|
+
} else if (value instanceof LiveObject.AbstractCrdt) {
|
|
1620
|
+
throw new Error("Unhandled subclass of AbstractCrdt encountered");
|
|
1621
|
+
}
|
|
1622
|
+
|
|
1623
|
+
if (Array.isArray(value)) {
|
|
1624
|
+
return lsonListToJson(value);
|
|
1625
|
+
} else if (isPlainObject(value)) {
|
|
1626
|
+
return lsonObjectToJson(value);
|
|
1627
|
+
}
|
|
1628
|
+
|
|
1629
|
+
return value;
|
|
1630
|
+
}
|
|
1631
|
+
|
|
1632
|
+
function isPlainObject(obj) {
|
|
1633
|
+
return obj !== null && Object.prototype.toString.call(obj) === "[object Object]";
|
|
1634
|
+
}
|
|
1635
|
+
|
|
1636
|
+
function anyToCrdt(obj) {
|
|
1637
|
+
if (obj == null) {
|
|
1638
|
+
return obj;
|
|
1639
|
+
}
|
|
1640
|
+
|
|
1641
|
+
if (Array.isArray(obj)) {
|
|
1642
|
+
return new LiveObject.LiveList(obj.map(anyToCrdt));
|
|
1643
|
+
}
|
|
1644
|
+
|
|
1645
|
+
if (isPlainObject(obj)) {
|
|
1646
|
+
var init = {};
|
|
1647
|
+
|
|
1648
|
+
for (var _key3 in obj) {
|
|
1649
|
+
init[_key3] = anyToCrdt(obj[_key3]);
|
|
1650
|
+
}
|
|
1651
|
+
|
|
1652
|
+
return new LiveObject.LiveObject(init);
|
|
1653
|
+
}
|
|
1654
|
+
|
|
1655
|
+
return obj;
|
|
1656
|
+
}
|
|
1657
|
+
|
|
1658
|
+
function patchLiveList(liveList, prev, next) {
|
|
1659
|
+
var i = 0;
|
|
1660
|
+
var prevEnd = prev.length - 1;
|
|
1661
|
+
var nextEnd = next.length - 1;
|
|
1662
|
+
var prevNode = prev[0];
|
|
1663
|
+
var nextNode = next[0];
|
|
1664
|
+
|
|
1665
|
+
outer: {
|
|
1666
|
+
while (prevNode === nextNode) {
|
|
1667
|
+
++i;
|
|
1668
|
+
|
|
1669
|
+
if (i > prevEnd || i > nextEnd) {
|
|
1670
|
+
break outer;
|
|
1671
|
+
}
|
|
1672
|
+
|
|
1673
|
+
prevNode = prev[i];
|
|
1674
|
+
nextNode = next[i];
|
|
1675
|
+
}
|
|
1676
|
+
|
|
1677
|
+
prevNode = prev[prevEnd];
|
|
1678
|
+
nextNode = next[nextEnd];
|
|
1679
|
+
|
|
1680
|
+
while (prevNode === nextNode) {
|
|
1681
|
+
prevEnd--;
|
|
1682
|
+
nextEnd--;
|
|
1683
|
+
|
|
1684
|
+
if (i > prevEnd || i > nextEnd) {
|
|
1685
|
+
break outer;
|
|
1686
|
+
}
|
|
1687
|
+
|
|
1688
|
+
prevNode = prev[prevEnd];
|
|
1689
|
+
nextNode = next[nextEnd];
|
|
1690
|
+
}
|
|
1691
|
+
}
|
|
1692
|
+
|
|
1693
|
+
if (i > prevEnd) {
|
|
1694
|
+
if (i <= nextEnd) {
|
|
1695
|
+
while (i <= nextEnd) {
|
|
1696
|
+
liveList.insert(anyToCrdt(next[i]), i);
|
|
1697
|
+
i++;
|
|
1698
|
+
}
|
|
1699
|
+
}
|
|
1700
|
+
} else if (i > nextEnd) {
|
|
1701
|
+
var localI = i;
|
|
1702
|
+
|
|
1703
|
+
while (localI <= prevEnd) {
|
|
1704
|
+
liveList.delete(i);
|
|
1705
|
+
localI++;
|
|
1706
|
+
}
|
|
1707
|
+
} else {
|
|
1708
|
+
while (i <= prevEnd && i <= nextEnd) {
|
|
1709
|
+
prevNode = prev[i];
|
|
1710
|
+
nextNode = next[i];
|
|
1711
|
+
var liveListNode = liveList.get(i);
|
|
1712
|
+
|
|
1713
|
+
if (liveListNode instanceof LiveObject.LiveObject && isPlainObject(prevNode) && isPlainObject(nextNode)) {
|
|
1714
|
+
patchLiveObject(liveListNode, prevNode, nextNode);
|
|
1715
|
+
} else {
|
|
1716
|
+
liveList.set(i, anyToCrdt(nextNode));
|
|
1717
|
+
}
|
|
1718
|
+
|
|
1719
|
+
i++;
|
|
1720
|
+
}
|
|
1721
|
+
|
|
1722
|
+
while (i <= nextEnd) {
|
|
1723
|
+
liveList.insert(anyToCrdt(next[i]), i);
|
|
1724
|
+
i++;
|
|
1725
|
+
}
|
|
1726
|
+
|
|
1727
|
+
var _localI = i;
|
|
1728
|
+
|
|
1729
|
+
while (_localI <= prevEnd) {
|
|
1730
|
+
liveList.delete(i);
|
|
1731
|
+
_localI++;
|
|
1732
|
+
}
|
|
1733
|
+
}
|
|
1734
|
+
}
|
|
1735
|
+
function patchLiveObjectKey(liveObject, key, prev, next) {
|
|
1736
|
+
if (process.env.NODE_ENV !== "production") {
|
|
1737
|
+
var nonSerializableValue = LiveObject.findNonSerializableValue(next);
|
|
1738
|
+
|
|
1739
|
+
if (nonSerializableValue) {
|
|
1740
|
+
console.error("New state path: '" + nonSerializableValue.path + "' value: '" + nonSerializableValue.value + "' is not serializable.\nOnly serializable value can be synced with Liveblocks.");
|
|
1741
|
+
return;
|
|
1742
|
+
}
|
|
1743
|
+
}
|
|
1744
|
+
|
|
1745
|
+
var value = liveObject.get(key);
|
|
1746
|
+
|
|
1747
|
+
if (next === undefined) {
|
|
1748
|
+
liveObject.delete(key);
|
|
1749
|
+
} else if (value === undefined) {
|
|
1750
|
+
liveObject.set(key, anyToCrdt(next));
|
|
1751
|
+
} else if (prev === next) {
|
|
1752
|
+
return;
|
|
1753
|
+
} else if (value instanceof LiveObject.LiveList && Array.isArray(prev) && Array.isArray(next)) {
|
|
1754
|
+
patchLiveList(value, prev, next);
|
|
1755
|
+
} else if (value instanceof LiveObject.LiveObject && isPlainObject(prev) && isPlainObject(next)) {
|
|
1756
|
+
patchLiveObject(value, prev, next);
|
|
1757
|
+
} else {
|
|
1758
|
+
liveObject.set(key, anyToCrdt(next));
|
|
1759
|
+
}
|
|
1760
|
+
}
|
|
1761
|
+
function patchLiveObject(root, prev, next) {
|
|
1762
|
+
var updates = {};
|
|
1763
|
+
|
|
1764
|
+
for (var _key4 in next) {
|
|
1765
|
+
patchLiveObjectKey(root, _key4, prev[_key4], next[_key4]);
|
|
1766
|
+
}
|
|
1767
|
+
|
|
1768
|
+
for (var _key5 in prev) {
|
|
1769
|
+
if (next[_key5] === undefined) {
|
|
1770
|
+
root.delete(_key5);
|
|
1771
|
+
}
|
|
1772
|
+
}
|
|
1773
|
+
|
|
1774
|
+
if (Object.keys(updates).length > 0) {
|
|
1775
|
+
root.update(updates);
|
|
1776
|
+
}
|
|
1777
|
+
}
|
|
1778
|
+
|
|
1779
|
+
function getParentsPath(node) {
|
|
1780
|
+
var path = [];
|
|
1781
|
+
|
|
1782
|
+
while (node._parentKey != null && node._parent != null) {
|
|
1783
|
+
if (node._parent instanceof LiveObject.LiveList) {
|
|
1784
|
+
path.push(node._parent._indexOfPosition(node._parentKey));
|
|
1785
|
+
} else {
|
|
1786
|
+
path.push(node._parentKey);
|
|
1787
|
+
}
|
|
1788
|
+
|
|
1789
|
+
node = node._parent;
|
|
1790
|
+
}
|
|
1791
|
+
|
|
1792
|
+
return path;
|
|
1793
|
+
}
|
|
1794
|
+
|
|
1795
|
+
function patchImmutableObject(state, updates) {
|
|
1796
|
+
return updates.reduce(function (state, update) {
|
|
1797
|
+
return patchImmutableObjectWithUpdate(state, update);
|
|
1798
|
+
}, state);
|
|
1799
|
+
}
|
|
1800
|
+
|
|
1801
|
+
function patchImmutableObjectWithUpdate(state, update) {
|
|
1802
|
+
var path = getParentsPath(update.node);
|
|
1803
|
+
return patchImmutableNode(state, path, update);
|
|
1804
|
+
}
|
|
1805
|
+
|
|
1806
|
+
function patchImmutableNode(state, path, update) {
|
|
1807
|
+
var pathItem = path.pop();
|
|
1808
|
+
|
|
1809
|
+
if (pathItem === undefined) {
|
|
1810
|
+
switch (update.type) {
|
|
1811
|
+
case "LiveObject":
|
|
1812
|
+
{
|
|
1813
|
+
if (typeof state !== "object") {
|
|
1814
|
+
throw new Error("Internal: received update on LiveObject but state was not an object");
|
|
1815
|
+
}
|
|
1816
|
+
|
|
1817
|
+
var newState = Object.assign({}, state);
|
|
1818
|
+
|
|
1819
|
+
for (var _key6 in update.updates) {
|
|
1820
|
+
var _update$updates$_key, _update$updates$_key2;
|
|
1821
|
+
|
|
1822
|
+
if (((_update$updates$_key = update.updates[_key6]) == null ? void 0 : _update$updates$_key.type) === "update") {
|
|
1823
|
+
var val = update.node.get(_key6);
|
|
1824
|
+
|
|
1825
|
+
if (val !== undefined) {
|
|
1826
|
+
newState[_key6] = lsonToJson(val);
|
|
1827
|
+
}
|
|
1828
|
+
} else if (((_update$updates$_key2 = update.updates[_key6]) == null ? void 0 : _update$updates$_key2.type) === "delete") {
|
|
1829
|
+
delete newState[_key6];
|
|
1830
|
+
}
|
|
1831
|
+
}
|
|
1832
|
+
|
|
1833
|
+
return newState;
|
|
1834
|
+
}
|
|
1835
|
+
|
|
1836
|
+
case "LiveList":
|
|
1837
|
+
{
|
|
1838
|
+
if (Array.isArray(state) === false) {
|
|
1839
|
+
throw new Error("Internal: received update on LiveList but state was not an array");
|
|
1840
|
+
}
|
|
1841
|
+
|
|
1842
|
+
var _newState = state.map(function (x) {
|
|
1843
|
+
return x;
|
|
1844
|
+
});
|
|
1845
|
+
|
|
1846
|
+
var _loop = function _loop() {
|
|
1847
|
+
var listUpdate = _step2.value;
|
|
1848
|
+
|
|
1849
|
+
if (listUpdate.type === "set") {
|
|
1850
|
+
_newState = _newState.map(function (item, index) {
|
|
1851
|
+
return index === listUpdate.index ? listUpdate.item : item;
|
|
1852
|
+
});
|
|
1853
|
+
} else if (listUpdate.type === "insert") {
|
|
1854
|
+
if (listUpdate.index === _newState.length) {
|
|
1855
|
+
_newState.push(lsonToJson(listUpdate.item));
|
|
1856
|
+
} else {
|
|
1857
|
+
_newState = [].concat(_newState.slice(0, listUpdate.index), [lsonToJson(listUpdate.item)], _newState.slice(listUpdate.index));
|
|
1858
|
+
}
|
|
1859
|
+
} else if (listUpdate.type === "delete") {
|
|
1860
|
+
_newState.splice(listUpdate.index, 1);
|
|
1861
|
+
} else if (listUpdate.type === "move") {
|
|
1862
|
+
if (listUpdate.previousIndex > listUpdate.index) {
|
|
1863
|
+
_newState = [].concat(_newState.slice(0, listUpdate.index), [lsonToJson(listUpdate.item)], _newState.slice(listUpdate.index, listUpdate.previousIndex), _newState.slice(listUpdate.previousIndex + 1));
|
|
1864
|
+
} else {
|
|
1865
|
+
_newState = [].concat(_newState.slice(0, listUpdate.previousIndex), _newState.slice(listUpdate.previousIndex + 1, listUpdate.index + 1), [lsonToJson(listUpdate.item)], _newState.slice(listUpdate.index + 1));
|
|
1866
|
+
}
|
|
1867
|
+
}
|
|
1868
|
+
};
|
|
1869
|
+
|
|
1870
|
+
for (var _iterator2 = LiveObject._createForOfIteratorHelperLoose(update.updates), _step2; !(_step2 = _iterator2()).done;) {
|
|
1871
|
+
_loop();
|
|
1872
|
+
}
|
|
1873
|
+
|
|
1874
|
+
return _newState;
|
|
1875
|
+
}
|
|
1876
|
+
|
|
1877
|
+
case "LiveMap":
|
|
1878
|
+
{
|
|
1879
|
+
if (typeof state !== "object") {
|
|
1880
|
+
throw new Error("Internal: received update on LiveMap but state was not an object");
|
|
1881
|
+
}
|
|
1882
|
+
|
|
1883
|
+
var _newState2 = Object.assign({}, state);
|
|
1884
|
+
|
|
1885
|
+
for (var _key7 in update.updates) {
|
|
1886
|
+
var _update$updates$_key3, _update$updates$_key4;
|
|
1887
|
+
|
|
1888
|
+
if (((_update$updates$_key3 = update.updates[_key7]) == null ? void 0 : _update$updates$_key3.type) === "update") {
|
|
1889
|
+
_newState2[_key7] = lsonToJson(update.node.get(_key7));
|
|
1890
|
+
} else if (((_update$updates$_key4 = update.updates[_key7]) == null ? void 0 : _update$updates$_key4.type) === "delete") {
|
|
1891
|
+
delete _newState2[_key7];
|
|
1892
|
+
}
|
|
1893
|
+
}
|
|
1894
|
+
|
|
1895
|
+
return _newState2;
|
|
1896
|
+
}
|
|
1897
|
+
}
|
|
1898
|
+
}
|
|
1899
|
+
|
|
1900
|
+
if (Array.isArray(state)) {
|
|
1901
|
+
var newArray = [].concat(state);
|
|
1902
|
+
newArray[pathItem] = patchImmutableNode(state[pathItem], path, update);
|
|
1903
|
+
return newArray;
|
|
1904
|
+
} else {
|
|
1905
|
+
var _extends2;
|
|
1906
|
+
|
|
1907
|
+
return LiveObject._extends({}, state, (_extends2 = {}, _extends2[pathItem] = patchImmutableNode(state[pathItem], path, update), _extends2));
|
|
1908
|
+
}
|
|
1909
|
+
}
|
|
1910
|
+
|
|
1911
|
+
var internals = {
|
|
1912
|
+
liveObjectToJson: liveObjectToJson,
|
|
1913
|
+
lsonToJson: lsonToJson,
|
|
1914
|
+
patchLiveList: patchLiveList,
|
|
1915
|
+
patchImmutableObject: patchImmutableObject,
|
|
1916
|
+
patchLiveObject: patchLiveObject,
|
|
1917
|
+
patchLiveObjectKey: patchLiveObjectKey
|
|
1918
|
+
};
|
|
1919
|
+
|
|
1920
|
+
exports.LiveList = LiveObject.LiveList;
|
|
1921
|
+
exports.LiveMap = LiveObject.LiveMap;
|
|
1922
|
+
exports.LiveObject = LiveObject.LiveObject;
|
|
1923
|
+
exports.createClient = createClient;
|
|
1924
|
+
exports.internals = internals;
|