@liveblocks/client 0.14.0-beta.1 → 0.14.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/lib/cjs/AbstractCrdt.d.ts +2 -1
- package/lib/cjs/LiveList.d.ts +2 -1
- package/lib/cjs/LiveList.js +26 -1
- package/lib/cjs/LiveMap.d.ts +1 -1
- package/lib/cjs/LiveMap.js +4 -1
- package/lib/cjs/LiveObject.d.ts +1 -1
- package/lib/cjs/LiveObject.js +35 -3
- package/lib/cjs/LiveRegister.d.ts +1 -1
- package/lib/cjs/LiveRegister.js +1 -1
- package/lib/cjs/client.js +50 -7
- package/lib/cjs/index.d.ts +1 -1
- package/lib/cjs/room.d.ts +9 -9
- package/lib/cjs/room.js +116 -68
- package/lib/cjs/types.d.ts +26 -1
- package/lib/esm/AbstractCrdt.d.ts +2 -1
- package/lib/esm/LiveList.d.ts +2 -1
- package/lib/esm/LiveList.js +26 -1
- package/lib/esm/LiveMap.d.ts +1 -1
- package/lib/esm/LiveMap.js +4 -1
- package/lib/esm/LiveObject.d.ts +1 -1
- package/lib/esm/LiveObject.js +35 -3
- package/lib/esm/LiveRegister.d.ts +1 -1
- package/lib/esm/LiveRegister.js +1 -1
- package/lib/esm/client.js +50 -7
- package/lib/esm/index.d.ts +1 -1
- package/lib/esm/room.d.ts +9 -9
- package/lib/esm/room.js +115 -48
- package/lib/esm/types.d.ts +26 -1
- package/package.json +6 -2
- package/lib/cjs/authentication.d.ts +0 -3
- package/lib/cjs/authentication.js +0 -71
- package/lib/esm/authentication.d.ts +0 -3
- package/lib/esm/authentication.js +0 -66
|
@@ -8,6 +8,7 @@ export declare type ApplyResult = {
|
|
|
8
8
|
export interface Doc {
|
|
9
9
|
generateId: () => string;
|
|
10
10
|
generateOpId: () => string;
|
|
11
|
+
getItem: (id: string) => AbstractCrdt | undefined;
|
|
11
12
|
addItem: (id: string, item: AbstractCrdt) => void;
|
|
12
13
|
deleteItem: (id: string) => void;
|
|
13
14
|
dispatch: (ops: Op[], reverseOps: Op[], modified: AbstractCrdt[]) => void;
|
|
@@ -45,7 +46,7 @@ export declare abstract class AbstractCrdt {
|
|
|
45
46
|
/**
|
|
46
47
|
* INTERNAL
|
|
47
48
|
*/
|
|
48
|
-
abstract _attachChild(id: string, key: string, crdt: AbstractCrdt, isLocal: boolean): ApplyResult;
|
|
49
|
+
abstract _attachChild(id: string, key: string, crdt: AbstractCrdt, opId: string, isLocal: boolean): ApplyResult;
|
|
49
50
|
/**
|
|
50
51
|
* INTERNAL
|
|
51
52
|
*/
|
package/lib/cjs/LiveList.d.ts
CHANGED
|
@@ -25,7 +25,7 @@ export declare class LiveList<T> extends AbstractCrdt {
|
|
|
25
25
|
/**
|
|
26
26
|
* INTERNAL
|
|
27
27
|
*/
|
|
28
|
-
_attachChild(id: string, key: string, child: AbstractCrdt, isLocal: boolean): ApplyResult;
|
|
28
|
+
_attachChild(id: string, key: string, child: AbstractCrdt, opId: string, isLocal: boolean): ApplyResult;
|
|
29
29
|
/**
|
|
30
30
|
* INTERNAL
|
|
31
31
|
*/
|
|
@@ -68,6 +68,7 @@ export declare class LiveList<T> extends AbstractCrdt {
|
|
|
68
68
|
* @param index The index of the element to delete
|
|
69
69
|
*/
|
|
70
70
|
delete(index: number): void;
|
|
71
|
+
clear(): void;
|
|
71
72
|
/**
|
|
72
73
|
* Returns an Array of all the elements in the LiveList.
|
|
73
74
|
*/
|
package/lib/cjs/LiveList.js
CHANGED
|
@@ -96,11 +96,14 @@ class LiveList extends AbstractCrdt_1.AbstractCrdt {
|
|
|
96
96
|
/**
|
|
97
97
|
* INTERNAL
|
|
98
98
|
*/
|
|
99
|
-
_attachChild(id, key, child, isLocal) {
|
|
99
|
+
_attachChild(id, key, child, opId, isLocal) {
|
|
100
100
|
var _a;
|
|
101
101
|
if (this._doc == null) {
|
|
102
102
|
throw new Error("Can't attach child if doc is not present");
|
|
103
103
|
}
|
|
104
|
+
if (this._doc.getItem(id) !== undefined) {
|
|
105
|
+
return { modified: false };
|
|
106
|
+
}
|
|
104
107
|
child._attach(id, this._doc);
|
|
105
108
|
child._setParentLink(this, key);
|
|
106
109
|
const index = __classPrivateFieldGet(this, _LiveList_items, "f").findIndex((entry) => entry[1] === key);
|
|
@@ -283,6 +286,28 @@ class LiveList extends AbstractCrdt_1.AbstractCrdt {
|
|
|
283
286
|
}
|
|
284
287
|
}
|
|
285
288
|
}
|
|
289
|
+
clear() {
|
|
290
|
+
if (this._doc) {
|
|
291
|
+
let ops = [];
|
|
292
|
+
let reverseOps = [];
|
|
293
|
+
for (const item of __classPrivateFieldGet(this, _LiveList_items, "f")) {
|
|
294
|
+
item[0]._detach();
|
|
295
|
+
const childId = item[0]._id;
|
|
296
|
+
if (childId) {
|
|
297
|
+
ops.push({ id: childId, type: live_1.OpType.DeleteCrdt });
|
|
298
|
+
reverseOps.push(...item[0]._serialize(this._id, item[1]));
|
|
299
|
+
}
|
|
300
|
+
}
|
|
301
|
+
__classPrivateFieldSet(this, _LiveList_items, [], "f");
|
|
302
|
+
this._doc.dispatch(ops, reverseOps, [this]);
|
|
303
|
+
}
|
|
304
|
+
else {
|
|
305
|
+
for (const item of __classPrivateFieldGet(this, _LiveList_items, "f")) {
|
|
306
|
+
item[0]._detach();
|
|
307
|
+
}
|
|
308
|
+
__classPrivateFieldSet(this, _LiveList_items, [], "f");
|
|
309
|
+
}
|
|
310
|
+
}
|
|
286
311
|
/**
|
|
287
312
|
* Returns an Array of all the elements in the LiveList.
|
|
288
313
|
*/
|
package/lib/cjs/LiveMap.d.ts
CHANGED
|
@@ -23,7 +23,7 @@ export declare class LiveMap<TKey extends string, TValue> extends AbstractCrdt {
|
|
|
23
23
|
/**
|
|
24
24
|
* INTERNAL
|
|
25
25
|
*/
|
|
26
|
-
_attachChild(id: string, key: TKey, child: AbstractCrdt, isLocal: boolean): ApplyResult;
|
|
26
|
+
_attachChild(id: string, key: TKey, child: AbstractCrdt, opId: string, isLocal: boolean): ApplyResult;
|
|
27
27
|
/**
|
|
28
28
|
* INTERNAL
|
|
29
29
|
*/
|
package/lib/cjs/LiveMap.js
CHANGED
|
@@ -100,10 +100,13 @@ class LiveMap extends AbstractCrdt_1.AbstractCrdt {
|
|
|
100
100
|
/**
|
|
101
101
|
* INTERNAL
|
|
102
102
|
*/
|
|
103
|
-
_attachChild(id, key, child, isLocal) {
|
|
103
|
+
_attachChild(id, key, child, opId, isLocal) {
|
|
104
104
|
if (this._doc == null) {
|
|
105
105
|
throw new Error("Can't attach child if doc is not present");
|
|
106
106
|
}
|
|
107
|
+
if (this._doc.getItem(id) !== undefined) {
|
|
108
|
+
return { modified: false };
|
|
109
|
+
}
|
|
107
110
|
const previousValue = __classPrivateFieldGet(this, _LiveMap_map, "f").get(key);
|
|
108
111
|
let reverse;
|
|
109
112
|
if (previousValue) {
|
package/lib/cjs/LiveObject.d.ts
CHANGED
|
@@ -27,7 +27,7 @@ export declare class LiveObject<T extends Record<string, any> = Record<string, a
|
|
|
27
27
|
/**
|
|
28
28
|
* INTERNAL
|
|
29
29
|
*/
|
|
30
|
-
_attachChild(id: string, key: keyof T, child: AbstractCrdt, isLocal: boolean): ApplyResult;
|
|
30
|
+
_attachChild(id: string, key: keyof T, child: AbstractCrdt, opId: string, isLocal: boolean): ApplyResult;
|
|
31
31
|
/**
|
|
32
32
|
* INTERNAL
|
|
33
33
|
*/
|
package/lib/cjs/LiveObject.js
CHANGED
|
@@ -106,10 +106,32 @@ class LiveObject extends AbstractCrdt_1.AbstractCrdt {
|
|
|
106
106
|
/**
|
|
107
107
|
* INTERNAL
|
|
108
108
|
*/
|
|
109
|
-
_attachChild(id, key, child, isLocal) {
|
|
109
|
+
_attachChild(id, key, child, opId, isLocal) {
|
|
110
110
|
if (this._doc == null) {
|
|
111
111
|
throw new Error("Can't attach child if doc is not present");
|
|
112
112
|
}
|
|
113
|
+
if (this._doc.getItem(id) !== undefined) {
|
|
114
|
+
if (__classPrivateFieldGet(this, _LiveObject_propToLastUpdate, "f").get(key) === opId) {
|
|
115
|
+
// Acknowlegment from local operation
|
|
116
|
+
__classPrivateFieldGet(this, _LiveObject_propToLastUpdate, "f").delete(key);
|
|
117
|
+
}
|
|
118
|
+
return { modified: false };
|
|
119
|
+
}
|
|
120
|
+
if (isLocal) {
|
|
121
|
+
__classPrivateFieldGet(this, _LiveObject_propToLastUpdate, "f").set(key, opId);
|
|
122
|
+
}
|
|
123
|
+
else if (__classPrivateFieldGet(this, _LiveObject_propToLastUpdate, "f").get(key) === undefined) {
|
|
124
|
+
// Remote operation with no local change => apply operation
|
|
125
|
+
}
|
|
126
|
+
else if (__classPrivateFieldGet(this, _LiveObject_propToLastUpdate, "f").get(key) === opId) {
|
|
127
|
+
// Acknowlegment from local operation
|
|
128
|
+
__classPrivateFieldGet(this, _LiveObject_propToLastUpdate, "f").delete(key);
|
|
129
|
+
return { modified: false };
|
|
130
|
+
}
|
|
131
|
+
else {
|
|
132
|
+
// Conflict, ignore remote operation
|
|
133
|
+
return { modified: false };
|
|
134
|
+
}
|
|
113
135
|
const previousValue = __classPrivateFieldGet(this, _LiveObject_map, "f").get(key);
|
|
114
136
|
let reverse;
|
|
115
137
|
if ((0, utils_1.isCrdt)(previousValue)) {
|
|
@@ -284,7 +306,6 @@ class LiveObject extends AbstractCrdt_1.AbstractCrdt {
|
|
|
284
306
|
data: {},
|
|
285
307
|
};
|
|
286
308
|
for (const key in overrides) {
|
|
287
|
-
__classPrivateFieldGet(this, _LiveObject_propToLastUpdate, "f").set(key, opId);
|
|
288
309
|
const oldValue = __classPrivateFieldGet(this, _LiveObject_map, "f").get(key);
|
|
289
310
|
if (oldValue instanceof AbstractCrdt_1.AbstractCrdt) {
|
|
290
311
|
reverseOps.push(...oldValue._serialize(this._id, key));
|
|
@@ -300,10 +321,16 @@ class LiveObject extends AbstractCrdt_1.AbstractCrdt {
|
|
|
300
321
|
if (newValue instanceof AbstractCrdt_1.AbstractCrdt) {
|
|
301
322
|
newValue._setParentLink(this, key);
|
|
302
323
|
newValue._attach(this._doc.generateId(), this._doc);
|
|
303
|
-
|
|
324
|
+
const newAttachChildOps = newValue._serialize(this._id, key, this._doc);
|
|
325
|
+
const createCrdtOp = newAttachChildOps.find((op) => op.parentId === this._id);
|
|
326
|
+
if (createCrdtOp) {
|
|
327
|
+
__classPrivateFieldGet(this, _LiveObject_propToLastUpdate, "f").set(key, createCrdtOp.opId);
|
|
328
|
+
}
|
|
329
|
+
ops.push(...newAttachChildOps);
|
|
304
330
|
}
|
|
305
331
|
else {
|
|
306
332
|
updatedProps[key] = newValue;
|
|
333
|
+
__classPrivateFieldGet(this, _LiveObject_propToLastUpdate, "f").set(key, opId);
|
|
307
334
|
}
|
|
308
335
|
__classPrivateFieldGet(this, _LiveObject_map, "f").set(key, newValue);
|
|
309
336
|
}
|
|
@@ -378,6 +405,11 @@ _LiveObject_map = new WeakMap(), _LiveObject_propToLastUpdate = new WeakMap(), _
|
|
|
378
405
|
if (__classPrivateFieldGet(this, _LiveObject_map, "f").has(key) === false) {
|
|
379
406
|
return { modified: false };
|
|
380
407
|
}
|
|
408
|
+
// If a local operation exists on the same key
|
|
409
|
+
// prevent flickering by not applying delete op.
|
|
410
|
+
if (__classPrivateFieldGet(this, _LiveObject_propToLastUpdate, "f").get(key) !== undefined) {
|
|
411
|
+
return { modified: false };
|
|
412
|
+
}
|
|
381
413
|
const oldValue = __classPrivateFieldGet(this, _LiveObject_map, "f").get(key);
|
|
382
414
|
let reverse = [];
|
|
383
415
|
if ((0, utils_1.isCrdt)(oldValue)) {
|
|
@@ -19,7 +19,7 @@ export declare class LiveRegister<TValue = any> extends AbstractCrdt {
|
|
|
19
19
|
* INTERNAL
|
|
20
20
|
*/
|
|
21
21
|
_toSerializedCrdt(): SerializedCrdt;
|
|
22
|
-
_attachChild(id: string, key: string, crdt: AbstractCrdt, isLocal: boolean): ApplyResult;
|
|
22
|
+
_attachChild(id: string, key: string, crdt: AbstractCrdt, opId: string, isLocal: boolean): ApplyResult;
|
|
23
23
|
_detachChild(crdt: AbstractCrdt): void;
|
|
24
24
|
_apply(op: Op, isLocal: boolean): ApplyResult;
|
|
25
25
|
}
|
package/lib/cjs/LiveRegister.js
CHANGED
package/lib/cjs/client.js
CHANGED
|
@@ -29,11 +29,7 @@ const room_1 = require("./room");
|
|
|
29
29
|
*/
|
|
30
30
|
function createClient(options) {
|
|
31
31
|
const clientOptions = options;
|
|
32
|
-
|
|
33
|
-
if (clientOptions.throttle < 80 || clientOptions.throttle > 1000) {
|
|
34
|
-
throw new Error("Liveblocks client throttle should be between 80 and 1000 ms");
|
|
35
|
-
}
|
|
36
|
-
}
|
|
32
|
+
const throttleDelay = getThrottleDelayFromOptions(options);
|
|
37
33
|
const rooms = new Map();
|
|
38
34
|
function getRoom(roomId) {
|
|
39
35
|
const internalRoom = rooms.get(roomId);
|
|
@@ -44,9 +40,21 @@ function createClient(options) {
|
|
|
44
40
|
if (internalRoom) {
|
|
45
41
|
return internalRoom.room;
|
|
46
42
|
}
|
|
47
|
-
internalRoom = (0, room_1.createRoom)(
|
|
43
|
+
internalRoom = (0, room_1.createRoom)({
|
|
44
|
+
defaultPresence: options.defaultPresence,
|
|
45
|
+
defaultStorageRoot: options.defaultStorageRoot,
|
|
46
|
+
}, {
|
|
47
|
+
room: roomId,
|
|
48
|
+
throttleDelay,
|
|
49
|
+
WebSocketPolyfill: clientOptions.WebSocketPolyfill,
|
|
50
|
+
fetchPolyfill: clientOptions.fetchPolyfill,
|
|
51
|
+
liveblocksServer: clientOptions.liveblocksServer || "wss://liveblocks.net/v5",
|
|
52
|
+
authentication: prepareAuthentication(clientOptions),
|
|
53
|
+
});
|
|
48
54
|
rooms.set(roomId, internalRoom);
|
|
49
|
-
|
|
55
|
+
if (!options.DO_NOT_USE_withoutConnecting) {
|
|
56
|
+
internalRoom.connect();
|
|
57
|
+
}
|
|
50
58
|
return internalRoom.room;
|
|
51
59
|
}
|
|
52
60
|
function leave(roomId) {
|
|
@@ -78,3 +86,38 @@ function createClient(options) {
|
|
|
78
86
|
};
|
|
79
87
|
}
|
|
80
88
|
exports.createClient = createClient;
|
|
89
|
+
function getThrottleDelayFromOptions(options) {
|
|
90
|
+
if (options.throttle === undefined) {
|
|
91
|
+
return 100;
|
|
92
|
+
}
|
|
93
|
+
if (typeof options.throttle !== "number" ||
|
|
94
|
+
options.throttle < 80 ||
|
|
95
|
+
options.throttle > 1000) {
|
|
96
|
+
throw new Error("throttle should be a number between 80 and 1000.");
|
|
97
|
+
}
|
|
98
|
+
return options.throttle;
|
|
99
|
+
}
|
|
100
|
+
function prepareAuthentication(clientOptions) {
|
|
101
|
+
// TODO: throw descriptive errors for invalid options
|
|
102
|
+
if (typeof clientOptions.publicApiKey === "string") {
|
|
103
|
+
return {
|
|
104
|
+
type: "public",
|
|
105
|
+
publicApiKey: clientOptions.publicApiKey,
|
|
106
|
+
url: clientOptions.publicAuthorizeEndpoint ||
|
|
107
|
+
"https://liveblocks.io/api/public/authorize",
|
|
108
|
+
};
|
|
109
|
+
}
|
|
110
|
+
else if (typeof clientOptions.authEndpoint === "string") {
|
|
111
|
+
return {
|
|
112
|
+
type: "private",
|
|
113
|
+
url: clientOptions.authEndpoint,
|
|
114
|
+
};
|
|
115
|
+
}
|
|
116
|
+
else if (typeof clientOptions.authEndpoint === "function") {
|
|
117
|
+
return {
|
|
118
|
+
type: "custom",
|
|
119
|
+
callback: clientOptions.authEndpoint,
|
|
120
|
+
};
|
|
121
|
+
}
|
|
122
|
+
throw new Error("Invalid Liveblocks client options. For more information: https://liveblocks.io/docs/api-reference/liveblocks-client#createClient");
|
|
123
|
+
}
|
package/lib/cjs/index.d.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
export { LiveObject } from "./LiveObject";
|
|
2
2
|
export { LiveMap } from "./LiveMap";
|
|
3
3
|
export { LiveList } from "./LiveList";
|
|
4
|
-
export type { Others, Presence, Room, Client, User } from "./types";
|
|
4
|
+
export type { Others, Presence, Room, Client, User, BroadcastOptions, } from "./types";
|
|
5
5
|
export { createClient } from "./client";
|
package/lib/cjs/room.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { Others, Presence,
|
|
1
|
+
import { Others, Presence, Room, MyPresenceCallback, OthersEventCallback, EventCallback, User, Connection, ErrorCallback, AuthenticationToken, ConnectionCallback, StorageCallback, StorageUpdate, BroadcastOptions, AuthorizeResponse, Authentication } from "./types";
|
|
2
2
|
import { ClientMessage, Op } from "./live";
|
|
3
3
|
import { LiveMap } from "./LiveMap";
|
|
4
4
|
import { LiveObject } from "./LiveObject";
|
|
@@ -66,7 +66,7 @@ export declare type State = {
|
|
|
66
66
|
offlineOperations: Map<string, Op>;
|
|
67
67
|
};
|
|
68
68
|
export declare type Effects = {
|
|
69
|
-
authenticate(): void;
|
|
69
|
+
authenticate(auth: (room: string) => Promise<AuthorizeResponse>, createWebSocket: (token: string) => WebSocket): void;
|
|
70
70
|
send(messages: ClientMessage[]): void;
|
|
71
71
|
delayFlush(delay: number): number;
|
|
72
72
|
startHeartbeatInterval(): number;
|
|
@@ -75,13 +75,13 @@ export declare type Effects = {
|
|
|
75
75
|
};
|
|
76
76
|
declare type Context = {
|
|
77
77
|
room: string;
|
|
78
|
-
authEndpoint: AuthEndpoint;
|
|
79
|
-
liveblocksServer: string;
|
|
80
78
|
throttleDelay: number;
|
|
81
|
-
|
|
79
|
+
fetchPolyfill?: typeof fetch;
|
|
80
|
+
WebSocketPolyfill?: typeof WebSocket;
|
|
81
|
+
authentication: Authentication;
|
|
82
|
+
liveblocksServer: string;
|
|
82
83
|
};
|
|
83
84
|
export declare function makeStateMachine(state: State, context: Context, mockedEffects?: Effects): {
|
|
84
|
-
onOpen: () => void;
|
|
85
85
|
onClose: (event: {
|
|
86
86
|
code: number;
|
|
87
87
|
wasClean: boolean;
|
|
@@ -126,7 +126,7 @@ export declare function makeStateMachine(state: State, context: Context, mockedE
|
|
|
126
126
|
updatePresence: <T_4 extends Presence>(overrides: Partial<T_4>, options?: {
|
|
127
127
|
addToHistory: boolean;
|
|
128
128
|
} | undefined) => void;
|
|
129
|
-
broadcastEvent: (event: any) => void;
|
|
129
|
+
broadcastEvent: (event: any, options?: BroadcastOptions) => void;
|
|
130
130
|
batch: (callback: () => void) => void;
|
|
131
131
|
undo: () => void;
|
|
132
132
|
redo: () => void;
|
|
@@ -152,8 +152,8 @@ export declare type InternalRoom = {
|
|
|
152
152
|
onNavigatorOnline: () => void;
|
|
153
153
|
onVisibilityChange: (visibilityState: VisibilityState) => void;
|
|
154
154
|
};
|
|
155
|
-
export declare function createRoom(
|
|
155
|
+
export declare function createRoom(options: {
|
|
156
156
|
defaultPresence?: Presence;
|
|
157
157
|
defaultStorageRoot?: Record<string, any>;
|
|
158
|
-
}): InternalRoom;
|
|
158
|
+
}, context: Context): InternalRoom;
|
|
159
159
|
export {};
|
package/lib/cjs/room.js
CHANGED
|
@@ -1,23 +1,4 @@
|
|
|
1
1
|
"use strict";
|
|
2
|
-
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
-
if (k2 === undefined) k2 = k;
|
|
4
|
-
Object.defineProperty(o, k2, { enumerable: true, get: function() { return m[k]; } });
|
|
5
|
-
}) : (function(o, m, k, k2) {
|
|
6
|
-
if (k2 === undefined) k2 = k;
|
|
7
|
-
o[k2] = m[k];
|
|
8
|
-
}));
|
|
9
|
-
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
10
|
-
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
11
|
-
}) : function(o, v) {
|
|
12
|
-
o["default"] = v;
|
|
13
|
-
});
|
|
14
|
-
var __importStar = (this && this.__importStar) || function (mod) {
|
|
15
|
-
if (mod && mod.__esModule) return mod;
|
|
16
|
-
var result = {};
|
|
17
|
-
if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
|
|
18
|
-
__setModuleDefault(result, mod);
|
|
19
|
-
return result;
|
|
20
|
-
};
|
|
21
2
|
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
|
|
22
3
|
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
|
|
23
4
|
return new (P || (P = Promise))(function (resolve, reject) {
|
|
@@ -30,7 +11,6 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, ge
|
|
|
30
11
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
31
12
|
exports.createRoom = exports.defaultState = exports.makeStateMachine = void 0;
|
|
32
13
|
const utils_1 = require("./utils");
|
|
33
|
-
const authentication_1 = __importStar(require("./authentication"));
|
|
34
14
|
const live_1 = require("./live");
|
|
35
15
|
const LiveMap_1 = require("./LiveMap");
|
|
36
16
|
const LiveObject_1 = require("./LiveObject");
|
|
@@ -58,6 +38,9 @@ function makeOthers(presenceMap) {
|
|
|
58
38
|
get count() {
|
|
59
39
|
return array.length;
|
|
60
40
|
},
|
|
41
|
+
[Symbol.iterator]() {
|
|
42
|
+
return array[Symbol.iterator]();
|
|
43
|
+
},
|
|
61
44
|
map(callback) {
|
|
62
45
|
return array.map(callback);
|
|
63
46
|
},
|
|
@@ -72,16 +55,12 @@ function log(...params) {
|
|
|
72
55
|
}
|
|
73
56
|
function makeStateMachine(state, context, mockedEffects) {
|
|
74
57
|
const effects = mockedEffects || {
|
|
75
|
-
authenticate() {
|
|
58
|
+
authenticate(auth, createWebSocket) {
|
|
76
59
|
return __awaiter(this, void 0, void 0, function* () {
|
|
77
60
|
try {
|
|
78
|
-
const token = yield (
|
|
79
|
-
const parsedToken =
|
|
80
|
-
const socket =
|
|
81
|
-
socket.addEventListener("message", onMessage);
|
|
82
|
-
socket.addEventListener("open", onOpen);
|
|
83
|
-
socket.addEventListener("close", onClose);
|
|
84
|
-
socket.addEventListener("error", onError);
|
|
61
|
+
const { token } = yield auth(context.room);
|
|
62
|
+
const parsedToken = parseToken(token);
|
|
63
|
+
const socket = createWebSocket(token);
|
|
85
64
|
authenticationSuccess(parsedToken, socket);
|
|
86
65
|
}
|
|
87
66
|
catch (er) {
|
|
@@ -184,6 +163,7 @@ function makeStateMachine(state, context, mockedEffects) {
|
|
|
184
163
|
function load(items) {
|
|
185
164
|
const [root, parentToChildren] = buildRootAndParentToChildren(items);
|
|
186
165
|
return LiveObject_1.LiveObject._deserialize(root, parentToChildren, {
|
|
166
|
+
getItem,
|
|
187
167
|
addItem,
|
|
188
168
|
deleteItem,
|
|
189
169
|
generateId,
|
|
@@ -359,31 +339,31 @@ function makeStateMachine(state, context, mockedEffects) {
|
|
|
359
339
|
}
|
|
360
340
|
case live_1.OpType.CreateObject: {
|
|
361
341
|
const parent = state.items.get(op.parentId);
|
|
362
|
-
if (parent == null
|
|
342
|
+
if (parent == null) {
|
|
363
343
|
return { modified: false };
|
|
364
344
|
}
|
|
365
|
-
return parent._attachChild(op.id, op.parentKey, new LiveObject_1.LiveObject(op.data), isLocal);
|
|
345
|
+
return parent._attachChild(op.id, op.parentKey, new LiveObject_1.LiveObject(op.data), op.opId, isLocal);
|
|
366
346
|
}
|
|
367
347
|
case live_1.OpType.CreateList: {
|
|
368
348
|
const parent = state.items.get(op.parentId);
|
|
369
|
-
if (parent == null
|
|
349
|
+
if (parent == null) {
|
|
370
350
|
return { modified: false };
|
|
371
351
|
}
|
|
372
|
-
return parent._attachChild(op.id, op.parentKey, new LiveList_1.LiveList(), isLocal);
|
|
352
|
+
return parent._attachChild(op.id, op.parentKey, new LiveList_1.LiveList(), op.opId, isLocal);
|
|
373
353
|
}
|
|
374
354
|
case live_1.OpType.CreateRegister: {
|
|
375
355
|
const parent = state.items.get(op.parentId);
|
|
376
|
-
if (parent == null
|
|
356
|
+
if (parent == null) {
|
|
377
357
|
return { modified: false };
|
|
378
358
|
}
|
|
379
|
-
return parent._attachChild(op.id, op.parentKey, new LiveRegister_1.LiveRegister(op.data), isLocal);
|
|
359
|
+
return parent._attachChild(op.id, op.parentKey, new LiveRegister_1.LiveRegister(op.data), op.opId, isLocal);
|
|
380
360
|
}
|
|
381
361
|
case live_1.OpType.CreateMap: {
|
|
382
362
|
const parent = state.items.get(op.parentId);
|
|
383
|
-
if (parent == null
|
|
363
|
+
if (parent == null) {
|
|
384
364
|
return { modified: false };
|
|
385
365
|
}
|
|
386
|
-
return parent._attachChild(op.id, op.parentKey, new LiveMap_1.LiveMap(), isLocal);
|
|
366
|
+
return parent._attachChild(op.id, op.parentKey, new LiveMap_1.LiveMap(), op.opId, isLocal);
|
|
387
367
|
}
|
|
388
368
|
}
|
|
389
369
|
return { modified: false };
|
|
@@ -430,15 +410,14 @@ See v0.13 release notes for more information.
|
|
|
430
410
|
: null;
|
|
431
411
|
}
|
|
432
412
|
function connect() {
|
|
433
|
-
if (typeof window === "undefined") {
|
|
434
|
-
return;
|
|
435
|
-
}
|
|
436
413
|
if (state.connection.state !== "closed" &&
|
|
437
414
|
state.connection.state !== "unavailable") {
|
|
438
415
|
return null;
|
|
439
416
|
}
|
|
417
|
+
const auth = prepareAuthEndpoint(context.authentication, context.fetchPolyfill);
|
|
418
|
+
const createWebSocket = prepareCreateWebSocket(context.liveblocksServer, context.WebSocketPolyfill);
|
|
440
419
|
updateConnection({ state: "authenticating" });
|
|
441
|
-
effects.authenticate();
|
|
420
|
+
effects.authenticate(auth, createWebSocket);
|
|
442
421
|
}
|
|
443
422
|
function updatePresence(overrides, options) {
|
|
444
423
|
const oldValues = {};
|
|
@@ -465,6 +444,10 @@ See v0.13 release notes for more information.
|
|
|
465
444
|
}
|
|
466
445
|
}
|
|
467
446
|
function authenticationSuccess(token, socket) {
|
|
447
|
+
socket.addEventListener("message", onMessage);
|
|
448
|
+
socket.addEventListener("open", onOpen);
|
|
449
|
+
socket.addEventListener("close", onClose);
|
|
450
|
+
socket.addEventListener("error", onError);
|
|
468
451
|
updateConnection({
|
|
469
452
|
state: "connecting",
|
|
470
453
|
id: token.actor,
|
|
@@ -475,7 +458,9 @@ See v0.13 release notes for more information.
|
|
|
475
458
|
state.socket = socket;
|
|
476
459
|
}
|
|
477
460
|
function authenticationFailure(error) {
|
|
478
|
-
|
|
461
|
+
if (process.env.NODE_ENV !== "production") {
|
|
462
|
+
console.error("Call to authentication endpoint failed", error);
|
|
463
|
+
}
|
|
479
464
|
updateConnection({ state: "unavailable" });
|
|
480
465
|
state.numberOfRetry++;
|
|
481
466
|
state.timeoutHandles.reconnect = effects.scheduleReconnect(getRetryDelay());
|
|
@@ -642,14 +627,20 @@ See v0.13 release notes for more information.
|
|
|
642
627
|
updateConnection({ state: "failed" });
|
|
643
628
|
const error = new LiveblocksError(event.reason, event.code);
|
|
644
629
|
for (const listener of state.listeners.error) {
|
|
645
|
-
|
|
630
|
+
if (process.env.NODE_ENV !== "production") {
|
|
631
|
+
console.error(`Connection to Liveblocks websocket server closed. Reason: ${error.message} (code: ${error.code})`);
|
|
632
|
+
}
|
|
646
633
|
listener(error);
|
|
647
634
|
}
|
|
648
635
|
}
|
|
649
636
|
else if (event.wasClean === false) {
|
|
650
|
-
updateConnection({ state: "unavailable" });
|
|
651
637
|
state.numberOfRetry++;
|
|
652
|
-
|
|
638
|
+
const delay = getRetryDelay();
|
|
639
|
+
if (process.env.NODE_ENV !== "production") {
|
|
640
|
+
console.warn(`Connection to Liveblocks websocket server closed (code: ${event.code}). Retrying in ${delay}ms.`);
|
|
641
|
+
}
|
|
642
|
+
updateConnection({ state: "unavailable" });
|
|
643
|
+
state.timeoutHandles.reconnect = effects.scheduleReconnect(delay);
|
|
653
644
|
}
|
|
654
645
|
else {
|
|
655
646
|
updateConnection({ state: "closed" });
|
|
@@ -690,7 +681,7 @@ See v0.13 release notes for more information.
|
|
|
690
681
|
}
|
|
691
682
|
clearTimeout(state.timeoutHandles.pongTimeout);
|
|
692
683
|
state.timeoutHandles.pongTimeout = effects.schedulePongTimeout();
|
|
693
|
-
if (state.socket.readyState ===
|
|
684
|
+
if (state.socket.readyState === state.socket.OPEN) {
|
|
694
685
|
state.socket.send("ping");
|
|
695
686
|
}
|
|
696
687
|
}
|
|
@@ -737,7 +728,7 @@ See v0.13 release notes for more information.
|
|
|
737
728
|
state.offlineOperations.set(op.opId, op);
|
|
738
729
|
});
|
|
739
730
|
}
|
|
740
|
-
if (state.socket == null || state.socket.readyState !==
|
|
731
|
+
if (state.socket == null || state.socket.readyState !== state.socket.OPEN) {
|
|
741
732
|
state.buffer.storageOperations = [];
|
|
742
733
|
return;
|
|
743
734
|
}
|
|
@@ -813,8 +804,10 @@ See v0.13 release notes for more information.
|
|
|
813
804
|
function getOthers() {
|
|
814
805
|
return state.others;
|
|
815
806
|
}
|
|
816
|
-
function broadcastEvent(event
|
|
817
|
-
|
|
807
|
+
function broadcastEvent(event, options = {
|
|
808
|
+
shouldQueueEventIfNotReady: false,
|
|
809
|
+
}) {
|
|
810
|
+
if (state.socket == null && options.shouldQueueEventIfNotReady == false) {
|
|
818
811
|
return;
|
|
819
812
|
}
|
|
820
813
|
state.buffer.messages.push({
|
|
@@ -939,7 +932,6 @@ See v0.13 release notes for more information.
|
|
|
939
932
|
}
|
|
940
933
|
return {
|
|
941
934
|
// Internal
|
|
942
|
-
onOpen,
|
|
943
935
|
onClose,
|
|
944
936
|
onMessage,
|
|
945
937
|
authenticationSuccess,
|
|
@@ -1029,26 +1021,9 @@ function defaultState(me, defaultStorageRoot) {
|
|
|
1029
1021
|
};
|
|
1030
1022
|
}
|
|
1031
1023
|
exports.defaultState = defaultState;
|
|
1032
|
-
function createRoom(
|
|
1033
|
-
const throttleDelay = options.throttle || 100;
|
|
1034
|
-
const liveblocksServer = options.liveblocksServer || "wss://liveblocks.net/v5";
|
|
1035
|
-
let authEndpoint;
|
|
1036
|
-
if (options.authEndpoint) {
|
|
1037
|
-
authEndpoint = options.authEndpoint;
|
|
1038
|
-
}
|
|
1039
|
-
else {
|
|
1040
|
-
const publicAuthorizeEndpoint = options.publicAuthorizeEndpoint ||
|
|
1041
|
-
"https://liveblocks.io/api/public/authorize";
|
|
1042
|
-
authEndpoint = publicAuthorizeEndpoint;
|
|
1043
|
-
}
|
|
1024
|
+
function createRoom(options, context) {
|
|
1044
1025
|
const state = defaultState(options.defaultPresence, options.defaultStorageRoot);
|
|
1045
|
-
const machine = makeStateMachine(state,
|
|
1046
|
-
throttleDelay,
|
|
1047
|
-
liveblocksServer,
|
|
1048
|
-
authEndpoint,
|
|
1049
|
-
room: name,
|
|
1050
|
-
publicApiKey: options.publicApiKey,
|
|
1051
|
-
});
|
|
1026
|
+
const machine = makeStateMachine(state, context);
|
|
1052
1027
|
const room = {
|
|
1053
1028
|
/////////////
|
|
1054
1029
|
// Core //
|
|
@@ -1093,3 +1068,76 @@ class LiveblocksError extends Error {
|
|
|
1093
1068
|
this.code = code;
|
|
1094
1069
|
}
|
|
1095
1070
|
}
|
|
1071
|
+
function parseToken(token) {
|
|
1072
|
+
const tokenParts = token.split(".");
|
|
1073
|
+
if (tokenParts.length !== 3) {
|
|
1074
|
+
throw new Error(`Authentication error. Liveblocks could not parse the response of your authentication endpoint`);
|
|
1075
|
+
}
|
|
1076
|
+
const data = JSON.parse(atob(tokenParts[1]));
|
|
1077
|
+
if (typeof data.actor !== "number") {
|
|
1078
|
+
throw new Error(`Authentication error. Liveblocks could not parse the response of your authentication endpoint`);
|
|
1079
|
+
}
|
|
1080
|
+
return data;
|
|
1081
|
+
}
|
|
1082
|
+
function prepareCreateWebSocket(liveblocksServer, WebSocketPolyfill) {
|
|
1083
|
+
if (typeof window === "undefined" && WebSocketPolyfill == null) {
|
|
1084
|
+
throw new Error("To use Liveblocks client in a non-dom environment, you need to provide a WebSocket polyfill.");
|
|
1085
|
+
}
|
|
1086
|
+
const ws = WebSocketPolyfill || WebSocket;
|
|
1087
|
+
return (token) => {
|
|
1088
|
+
return new ws(`${liveblocksServer}/?token=${token}`);
|
|
1089
|
+
};
|
|
1090
|
+
}
|
|
1091
|
+
function prepareAuthEndpoint(authentication, fetchPolyfill) {
|
|
1092
|
+
if (authentication.type === "public") {
|
|
1093
|
+
if (typeof window === "undefined" && fetchPolyfill == null) {
|
|
1094
|
+
throw new Error("To use Liveblocks client in a non-dom environment with a publicApiKey, you need to provide a fetch polyfill.");
|
|
1095
|
+
}
|
|
1096
|
+
return (room) => fetchAuthEndpoint(fetchPolyfill || fetch, authentication.url, {
|
|
1097
|
+
room,
|
|
1098
|
+
publicApiKey: authentication.publicApiKey,
|
|
1099
|
+
});
|
|
1100
|
+
}
|
|
1101
|
+
if (authentication.type === "private") {
|
|
1102
|
+
if (typeof window === "undefined" && fetchPolyfill == null) {
|
|
1103
|
+
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.");
|
|
1104
|
+
}
|
|
1105
|
+
return (room) => fetchAuthEndpoint(fetchPolyfill || fetch, authentication.url, {
|
|
1106
|
+
room,
|
|
1107
|
+
});
|
|
1108
|
+
}
|
|
1109
|
+
if (authentication.type === "custom") {
|
|
1110
|
+
return authentication.callback;
|
|
1111
|
+
}
|
|
1112
|
+
throw new Error("Internal error. Unexpected authentication type");
|
|
1113
|
+
}
|
|
1114
|
+
function fetchAuthEndpoint(fetch, endpoint, body) {
|
|
1115
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
1116
|
+
const res = yield fetch(endpoint, {
|
|
1117
|
+
method: "POST",
|
|
1118
|
+
headers: {
|
|
1119
|
+
"Content-Type": "application/json",
|
|
1120
|
+
},
|
|
1121
|
+
body: JSON.stringify(body),
|
|
1122
|
+
});
|
|
1123
|
+
if (!res.ok) {
|
|
1124
|
+
throw new AuthenticationError(`Authentication error. Liveblocks could not parse the response of your authentication "${endpoint}"`);
|
|
1125
|
+
}
|
|
1126
|
+
let authResponse = null;
|
|
1127
|
+
try {
|
|
1128
|
+
authResponse = yield res.json();
|
|
1129
|
+
}
|
|
1130
|
+
catch (er) {
|
|
1131
|
+
throw new AuthenticationError(`Authentication error. Liveblocks could not parse the response of your authentication "${endpoint}"`);
|
|
1132
|
+
}
|
|
1133
|
+
if (typeof authResponse.token !== "string") {
|
|
1134
|
+
throw new AuthenticationError(`Authentication error. Liveblocks could not parse the response of your authentication "${endpoint}"`);
|
|
1135
|
+
}
|
|
1136
|
+
return authResponse;
|
|
1137
|
+
});
|
|
1138
|
+
}
|
|
1139
|
+
class AuthenticationError extends Error {
|
|
1140
|
+
constructor(message) {
|
|
1141
|
+
super(message);
|
|
1142
|
+
}
|
|
1143
|
+
}
|