@liveblocks/client 0.15.0-alpha.2 → 0.15.0-alpha.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/lib/cjs/AbstractCrdt.d.ts +2 -1
- package/lib/cjs/LiveList.d.ts +1 -1
- package/lib/cjs/LiveList.js +4 -1
- package/lib/cjs/LiveMap.d.ts +1 -1
- package/lib/cjs/LiveMap.js +4 -1
- package/lib/cjs/LiveObject.d.ts +1 -1
- package/lib/cjs/LiveObject.js +35 -3
- package/lib/cjs/LiveRegister.d.ts +1 -1
- package/lib/cjs/LiveRegister.js +1 -1
- package/lib/cjs/client.js +50 -7
- package/lib/cjs/immutable.js +8 -0
- package/lib/cjs/room.d.ts +8 -8
- package/lib/cjs/room.js +97 -62
- package/lib/cjs/types.d.ts +13 -0
- package/lib/cjs/utils.d.ts +4 -0
- package/lib/cjs/utils.js +51 -1
- package/lib/esm/AbstractCrdt.d.ts +2 -1
- package/lib/esm/LiveList.d.ts +1 -1
- package/lib/esm/LiveList.js +4 -1
- package/lib/esm/LiveMap.d.ts +1 -1
- package/lib/esm/LiveMap.js +4 -1
- package/lib/esm/LiveObject.d.ts +1 -1
- package/lib/esm/LiveObject.js +35 -3
- package/lib/esm/LiveRegister.d.ts +1 -1
- package/lib/esm/LiveRegister.js +1 -1
- package/lib/esm/client.js +50 -7
- package/lib/esm/immutable.js +8 -0
- package/lib/esm/room.d.ts +8 -8
- package/lib/esm/room.js +96 -42
- package/lib/esm/types.d.ts +13 -0
- package/lib/esm/utils.d.ts +4 -0
- package/lib/esm/utils.js +49 -0
- package/package.json +8 -3
- 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
|
@@ -9,6 +9,7 @@ export declare type ApplyResult = {
|
|
|
9
9
|
export interface Doc {
|
|
10
10
|
generateId: () => string;
|
|
11
11
|
generateOpId: () => string;
|
|
12
|
+
getItem: (id: string) => AbstractCrdt | undefined;
|
|
12
13
|
addItem: (id: string, item: AbstractCrdt) => void;
|
|
13
14
|
deleteItem: (id: string) => void;
|
|
14
15
|
dispatch: (ops: Op[], reverseOps: Op[], storageUpdates: Map<string, StorageUpdate>) => void;
|
|
@@ -46,7 +47,7 @@ export declare abstract class AbstractCrdt {
|
|
|
46
47
|
/**
|
|
47
48
|
* INTERNAL
|
|
48
49
|
*/
|
|
49
|
-
abstract _attachChild(id: string, key: string, crdt: AbstractCrdt, isLocal: boolean): ApplyResult;
|
|
50
|
+
abstract _attachChild(id: string, key: string, crdt: AbstractCrdt, opId: string, isLocal: boolean): ApplyResult;
|
|
50
51
|
/**
|
|
51
52
|
* INTERNAL
|
|
52
53
|
*/
|
package/lib/cjs/LiveList.d.ts
CHANGED
|
@@ -26,7 +26,7 @@ export declare class LiveList<T> extends AbstractCrdt {
|
|
|
26
26
|
/**
|
|
27
27
|
* INTERNAL
|
|
28
28
|
*/
|
|
29
|
-
_attachChild(id: string, key: string, child: AbstractCrdt, isLocal: boolean): ApplyResult;
|
|
29
|
+
_attachChild(id: string, key: string, child: AbstractCrdt, opId: string, isLocal: boolean): ApplyResult;
|
|
30
30
|
/**
|
|
31
31
|
* INTERNAL
|
|
32
32
|
*/
|
package/lib/cjs/LiveList.js
CHANGED
|
@@ -100,11 +100,14 @@ class LiveList 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
|
var _a;
|
|
105
105
|
if (this._doc == null) {
|
|
106
106
|
throw new Error("Can't attach child if doc is not present");
|
|
107
107
|
}
|
|
108
|
+
if (this._doc.getItem(id) !== undefined) {
|
|
109
|
+
return { modified: false };
|
|
110
|
+
}
|
|
108
111
|
child._attach(id, this._doc);
|
|
109
112
|
child._setParentLink(this, key);
|
|
110
113
|
const index = __classPrivateFieldGet(this, _LiveList_items, "f").findIndex((entry) => entry[1] === key);
|
package/lib/cjs/LiveMap.d.ts
CHANGED
|
@@ -23,7 +23,7 @@ export declare class LiveMap<TKey extends string, TValue> extends AbstractCrdt {
|
|
|
23
23
|
/**
|
|
24
24
|
* INTERNAL
|
|
25
25
|
*/
|
|
26
|
-
_attachChild(id: string, key: TKey, child: AbstractCrdt, isLocal: boolean): ApplyResult;
|
|
26
|
+
_attachChild(id: string, key: TKey, child: AbstractCrdt, opId: string, isLocal: boolean): ApplyResult;
|
|
27
27
|
/**
|
|
28
28
|
* INTERNAL
|
|
29
29
|
*/
|
package/lib/cjs/LiveMap.js
CHANGED
|
@@ -100,10 +100,13 @@ class LiveMap extends AbstractCrdt_1.AbstractCrdt {
|
|
|
100
100
|
/**
|
|
101
101
|
* INTERNAL
|
|
102
102
|
*/
|
|
103
|
-
_attachChild(id, key, child, isLocal) {
|
|
103
|
+
_attachChild(id, key, child, opId, isLocal) {
|
|
104
104
|
if (this._doc == null) {
|
|
105
105
|
throw new Error("Can't attach child if doc is not present");
|
|
106
106
|
}
|
|
107
|
+
if (this._doc.getItem(id) !== undefined) {
|
|
108
|
+
return { modified: false };
|
|
109
|
+
}
|
|
107
110
|
const previousValue = __classPrivateFieldGet(this, _LiveMap_map, "f").get(key);
|
|
108
111
|
let reverse;
|
|
109
112
|
if (previousValue) {
|
package/lib/cjs/LiveObject.d.ts
CHANGED
|
@@ -27,7 +27,7 @@ export declare class LiveObject<T extends Record<string, any> = Record<string, a
|
|
|
27
27
|
/**
|
|
28
28
|
* INTERNAL
|
|
29
29
|
*/
|
|
30
|
-
_attachChild(id: string, key: keyof T, child: AbstractCrdt, isLocal: boolean): ApplyResult;
|
|
30
|
+
_attachChild(id: string, key: keyof T, child: AbstractCrdt, opId: string, isLocal: boolean): ApplyResult;
|
|
31
31
|
/**
|
|
32
32
|
* INTERNAL
|
|
33
33
|
*/
|
package/lib/cjs/LiveObject.js
CHANGED
|
@@ -106,10 +106,32 @@ class LiveObject extends AbstractCrdt_1.AbstractCrdt {
|
|
|
106
106
|
/**
|
|
107
107
|
* INTERNAL
|
|
108
108
|
*/
|
|
109
|
-
_attachChild(id, key, child, isLocal) {
|
|
109
|
+
_attachChild(id, key, child, opId, isLocal) {
|
|
110
110
|
if (this._doc == null) {
|
|
111
111
|
throw new Error("Can't attach child if doc is not present");
|
|
112
112
|
}
|
|
113
|
+
if (this._doc.getItem(id) !== undefined) {
|
|
114
|
+
if (__classPrivateFieldGet(this, _LiveObject_propToLastUpdate, "f").get(key) === opId) {
|
|
115
|
+
// Acknowlegment from local operation
|
|
116
|
+
__classPrivateFieldGet(this, _LiveObject_propToLastUpdate, "f").delete(key);
|
|
117
|
+
}
|
|
118
|
+
return { modified: false };
|
|
119
|
+
}
|
|
120
|
+
if (isLocal) {
|
|
121
|
+
__classPrivateFieldGet(this, _LiveObject_propToLastUpdate, "f").set(key, opId);
|
|
122
|
+
}
|
|
123
|
+
else if (__classPrivateFieldGet(this, _LiveObject_propToLastUpdate, "f").get(key) === undefined) {
|
|
124
|
+
// Remote operation with no local change => apply operation
|
|
125
|
+
}
|
|
126
|
+
else if (__classPrivateFieldGet(this, _LiveObject_propToLastUpdate, "f").get(key) === opId) {
|
|
127
|
+
// Acknowlegment from local operation
|
|
128
|
+
__classPrivateFieldGet(this, _LiveObject_propToLastUpdate, "f").delete(key);
|
|
129
|
+
return { modified: false };
|
|
130
|
+
}
|
|
131
|
+
else {
|
|
132
|
+
// Conflict, ignore remote operation
|
|
133
|
+
return { modified: false };
|
|
134
|
+
}
|
|
113
135
|
const previousValue = __classPrivateFieldGet(this, _LiveObject_map, "f").get(key);
|
|
114
136
|
let reverse;
|
|
115
137
|
if ((0, utils_1.isCrdt)(previousValue)) {
|
|
@@ -314,7 +336,6 @@ class LiveObject extends AbstractCrdt_1.AbstractCrdt {
|
|
|
314
336
|
};
|
|
315
337
|
const updateDelta = {};
|
|
316
338
|
for (const key in overrides) {
|
|
317
|
-
__classPrivateFieldGet(this, _LiveObject_propToLastUpdate, "f").set(key, opId);
|
|
318
339
|
const oldValue = __classPrivateFieldGet(this, _LiveObject_map, "f").get(key);
|
|
319
340
|
if (oldValue instanceof AbstractCrdt_1.AbstractCrdt) {
|
|
320
341
|
reverseOps.push(...oldValue._serialize(this._id, key));
|
|
@@ -330,10 +351,16 @@ class LiveObject extends AbstractCrdt_1.AbstractCrdt {
|
|
|
330
351
|
if (newValue instanceof AbstractCrdt_1.AbstractCrdt) {
|
|
331
352
|
newValue._setParentLink(this, key);
|
|
332
353
|
newValue._attach(this._doc.generateId(), this._doc);
|
|
333
|
-
|
|
354
|
+
const newAttachChildOps = newValue._serialize(this._id, key, this._doc);
|
|
355
|
+
const createCrdtOp = newAttachChildOps.find((op) => op.parentId === this._id);
|
|
356
|
+
if (createCrdtOp) {
|
|
357
|
+
__classPrivateFieldGet(this, _LiveObject_propToLastUpdate, "f").set(key, createCrdtOp.opId);
|
|
358
|
+
}
|
|
359
|
+
ops.push(...newAttachChildOps);
|
|
334
360
|
}
|
|
335
361
|
else {
|
|
336
362
|
updatedProps[key] = newValue;
|
|
363
|
+
__classPrivateFieldGet(this, _LiveObject_propToLastUpdate, "f").set(key, opId);
|
|
337
364
|
}
|
|
338
365
|
__classPrivateFieldGet(this, _LiveObject_map, "f").set(key, newValue);
|
|
339
366
|
updateDelta[key] = { type: "update" };
|
|
@@ -426,6 +453,11 @@ _LiveObject_map = new WeakMap(), _LiveObject_propToLastUpdate = new WeakMap(), _
|
|
|
426
453
|
if (__classPrivateFieldGet(this, _LiveObject_map, "f").has(key) === false) {
|
|
427
454
|
return { modified: false };
|
|
428
455
|
}
|
|
456
|
+
// If a local operation exists on the same key
|
|
457
|
+
// prevent flickering by not applying delete op.
|
|
458
|
+
if (__classPrivateFieldGet(this, _LiveObject_propToLastUpdate, "f").get(key) !== undefined) {
|
|
459
|
+
return { modified: false };
|
|
460
|
+
}
|
|
429
461
|
const oldValue = __classPrivateFieldGet(this, _LiveObject_map, "f").get(key);
|
|
430
462
|
let reverse = [];
|
|
431
463
|
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): ApplyResult;
|
|
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/immutable.js
CHANGED
|
@@ -5,6 +5,7 @@ const LiveList_1 = require("./LiveList");
|
|
|
5
5
|
const LiveMap_1 = require("./LiveMap");
|
|
6
6
|
const LiveObject_1 = require("./LiveObject");
|
|
7
7
|
const LiveRegister_1 = require("./LiveRegister");
|
|
8
|
+
const utils_1 = require("./utils");
|
|
8
9
|
function liveObjectToJson(liveObject) {
|
|
9
10
|
const result = {};
|
|
10
11
|
const obj = liveObject.toObject();
|
|
@@ -140,6 +141,13 @@ function patchLiveList(liveList, prev, next) {
|
|
|
140
141
|
}
|
|
141
142
|
exports.patchLiveList = patchLiveList;
|
|
142
143
|
function patchLiveObjectKey(liveObject, key, prev, next) {
|
|
144
|
+
if (process.env.NODE_ENV !== "production") {
|
|
145
|
+
const nonSerializableValue = (0, utils_1.findNonSerializableValue)(next);
|
|
146
|
+
if (nonSerializableValue) {
|
|
147
|
+
console.error(`New state path: '${nonSerializableValue.path}' value: '${nonSerializableValue.value}' is not serializable.\nOnly serializable value can be synced with Liveblocks.`);
|
|
148
|
+
return;
|
|
149
|
+
}
|
|
150
|
+
}
|
|
143
151
|
const value = liveObject.get(key);
|
|
144
152
|
if (next === undefined) {
|
|
145
153
|
liveObject.delete(key);
|
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;
|
|
@@ -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");
|
|
@@ -75,16 +55,12 @@ function log(...params) {
|
|
|
75
55
|
}
|
|
76
56
|
function makeStateMachine(state, context, mockedEffects) {
|
|
77
57
|
const effects = mockedEffects || {
|
|
78
|
-
authenticate() {
|
|
58
|
+
authenticate(auth, createWebSocket) {
|
|
79
59
|
return __awaiter(this, void 0, void 0, function* () {
|
|
80
60
|
try {
|
|
81
|
-
const token = yield (
|
|
82
|
-
const parsedToken =
|
|
83
|
-
const socket =
|
|
84
|
-
socket.addEventListener("message", onMessage);
|
|
85
|
-
socket.addEventListener("open", onOpen);
|
|
86
|
-
socket.addEventListener("close", onClose);
|
|
87
|
-
socket.addEventListener("error", onError);
|
|
61
|
+
const { token } = yield auth(context.room);
|
|
62
|
+
const parsedToken = parseToken(token);
|
|
63
|
+
const socket = createWebSocket(token);
|
|
88
64
|
authenticationSuccess(parsedToken, socket);
|
|
89
65
|
}
|
|
90
66
|
catch (er) {
|
|
@@ -187,6 +163,7 @@ function makeStateMachine(state, context, mockedEffects) {
|
|
|
187
163
|
function load(items) {
|
|
188
164
|
const [root, parentToChildren] = buildRootAndParentToChildren(items);
|
|
189
165
|
return LiveObject_1.LiveObject._deserialize(root, parentToChildren, {
|
|
166
|
+
getItem,
|
|
190
167
|
addItem,
|
|
191
168
|
deleteItem,
|
|
192
169
|
generateId,
|
|
@@ -341,31 +318,31 @@ function makeStateMachine(state, context, mockedEffects) {
|
|
|
341
318
|
}
|
|
342
319
|
case live_1.OpType.CreateObject: {
|
|
343
320
|
const parent = state.items.get(op.parentId);
|
|
344
|
-
if (parent == null
|
|
321
|
+
if (parent == null) {
|
|
345
322
|
return { modified: false };
|
|
346
323
|
}
|
|
347
|
-
return parent._attachChild(op.id, op.parentKey, new LiveObject_1.LiveObject(op.data), isLocal);
|
|
324
|
+
return parent._attachChild(op.id, op.parentKey, new LiveObject_1.LiveObject(op.data), op.opId, isLocal);
|
|
348
325
|
}
|
|
349
326
|
case live_1.OpType.CreateList: {
|
|
350
327
|
const parent = state.items.get(op.parentId);
|
|
351
|
-
if (parent == null
|
|
328
|
+
if (parent == null) {
|
|
352
329
|
return { modified: false };
|
|
353
330
|
}
|
|
354
|
-
return parent._attachChild(op.id, op.parentKey, new LiveList_1.LiveList(), isLocal);
|
|
331
|
+
return parent._attachChild(op.id, op.parentKey, new LiveList_1.LiveList(), op.opId, isLocal);
|
|
355
332
|
}
|
|
356
333
|
case live_1.OpType.CreateRegister: {
|
|
357
334
|
const parent = state.items.get(op.parentId);
|
|
358
|
-
if (parent == null
|
|
335
|
+
if (parent == null) {
|
|
359
336
|
return { modified: false };
|
|
360
337
|
}
|
|
361
|
-
return parent._attachChild(op.id, op.parentKey, new LiveRegister_1.LiveRegister(op.data), isLocal);
|
|
338
|
+
return parent._attachChild(op.id, op.parentKey, new LiveRegister_1.LiveRegister(op.data), op.opId, isLocal);
|
|
362
339
|
}
|
|
363
340
|
case live_1.OpType.CreateMap: {
|
|
364
341
|
const parent = state.items.get(op.parentId);
|
|
365
|
-
if (parent == null
|
|
342
|
+
if (parent == null) {
|
|
366
343
|
return { modified: false };
|
|
367
344
|
}
|
|
368
|
-
return parent._attachChild(op.id, op.parentKey, new LiveMap_1.LiveMap(), isLocal);
|
|
345
|
+
return parent._attachChild(op.id, op.parentKey, new LiveMap_1.LiveMap(), op.opId, isLocal);
|
|
369
346
|
}
|
|
370
347
|
}
|
|
371
348
|
return { modified: false };
|
|
@@ -412,15 +389,14 @@ See v0.13 release notes for more information.
|
|
|
412
389
|
: null;
|
|
413
390
|
}
|
|
414
391
|
function connect() {
|
|
415
|
-
if (typeof window === "undefined") {
|
|
416
|
-
return;
|
|
417
|
-
}
|
|
418
392
|
if (state.connection.state !== "closed" &&
|
|
419
393
|
state.connection.state !== "unavailable") {
|
|
420
394
|
return null;
|
|
421
395
|
}
|
|
396
|
+
const auth = prepareAuthEndpoint(context.authentication, context.fetchPolyfill);
|
|
397
|
+
const createWebSocket = prepareCreateWebSocket(context.liveblocksServer, context.WebSocketPolyfill);
|
|
422
398
|
updateConnection({ state: "authenticating" });
|
|
423
|
-
effects.authenticate();
|
|
399
|
+
effects.authenticate(auth, createWebSocket);
|
|
424
400
|
}
|
|
425
401
|
function updatePresence(overrides, options) {
|
|
426
402
|
const oldValues = {};
|
|
@@ -447,6 +423,10 @@ See v0.13 release notes for more information.
|
|
|
447
423
|
}
|
|
448
424
|
}
|
|
449
425
|
function authenticationSuccess(token, socket) {
|
|
426
|
+
socket.addEventListener("message", onMessage);
|
|
427
|
+
socket.addEventListener("open", onOpen);
|
|
428
|
+
socket.addEventListener("close", onClose);
|
|
429
|
+
socket.addEventListener("error", onError);
|
|
450
430
|
updateConnection({
|
|
451
431
|
state: "connecting",
|
|
452
432
|
id: token.actor,
|
|
@@ -680,7 +660,7 @@ See v0.13 release notes for more information.
|
|
|
680
660
|
}
|
|
681
661
|
clearTimeout(state.timeoutHandles.pongTimeout);
|
|
682
662
|
state.timeoutHandles.pongTimeout = effects.schedulePongTimeout();
|
|
683
|
-
if (state.socket.readyState ===
|
|
663
|
+
if (state.socket.readyState === state.socket.OPEN) {
|
|
684
664
|
state.socket.send("ping");
|
|
685
665
|
}
|
|
686
666
|
}
|
|
@@ -727,7 +707,7 @@ See v0.13 release notes for more information.
|
|
|
727
707
|
state.offlineOperations.set(op.opId, op);
|
|
728
708
|
});
|
|
729
709
|
}
|
|
730
|
-
if (state.socket == null || state.socket.readyState !==
|
|
710
|
+
if (state.socket == null || state.socket.readyState !== state.socket.OPEN) {
|
|
731
711
|
state.buffer.storageOperations = [];
|
|
732
712
|
return;
|
|
733
713
|
}
|
|
@@ -934,7 +914,6 @@ See v0.13 release notes for more information.
|
|
|
934
914
|
}
|
|
935
915
|
return {
|
|
936
916
|
// Internal
|
|
937
|
-
onOpen,
|
|
938
917
|
onClose,
|
|
939
918
|
onMessage,
|
|
940
919
|
authenticationSuccess,
|
|
@@ -1028,26 +1007,9 @@ function defaultState(me, defaultStorageRoot) {
|
|
|
1028
1007
|
};
|
|
1029
1008
|
}
|
|
1030
1009
|
exports.defaultState = defaultState;
|
|
1031
|
-
function createRoom(
|
|
1032
|
-
const throttleDelay = options.throttle || 100;
|
|
1033
|
-
const liveblocksServer = options.liveblocksServer || "wss://liveblocks.net/v5";
|
|
1034
|
-
let authEndpoint;
|
|
1035
|
-
if (options.authEndpoint) {
|
|
1036
|
-
authEndpoint = options.authEndpoint;
|
|
1037
|
-
}
|
|
1038
|
-
else {
|
|
1039
|
-
const publicAuthorizeEndpoint = options.publicAuthorizeEndpoint ||
|
|
1040
|
-
"https://liveblocks.io/api/public/authorize";
|
|
1041
|
-
authEndpoint = publicAuthorizeEndpoint;
|
|
1042
|
-
}
|
|
1010
|
+
function createRoom(options, context) {
|
|
1043
1011
|
const state = defaultState(options.defaultPresence, options.defaultStorageRoot);
|
|
1044
|
-
const machine = makeStateMachine(state,
|
|
1045
|
-
throttleDelay,
|
|
1046
|
-
liveblocksServer,
|
|
1047
|
-
authEndpoint,
|
|
1048
|
-
room: name,
|
|
1049
|
-
publicApiKey: options.publicApiKey,
|
|
1050
|
-
});
|
|
1012
|
+
const machine = makeStateMachine(state, context);
|
|
1051
1013
|
const room = {
|
|
1052
1014
|
/////////////
|
|
1053
1015
|
// Core //
|
|
@@ -1092,3 +1054,76 @@ class LiveblocksError extends Error {
|
|
|
1092
1054
|
this.code = code;
|
|
1093
1055
|
}
|
|
1094
1056
|
}
|
|
1057
|
+
function parseToken(token) {
|
|
1058
|
+
const tokenParts = token.split(".");
|
|
1059
|
+
if (tokenParts.length !== 3) {
|
|
1060
|
+
throw new Error(`Authentication error. Liveblocks could not parse the response of your authentication endpoint`);
|
|
1061
|
+
}
|
|
1062
|
+
const data = JSON.parse(atob(tokenParts[1]));
|
|
1063
|
+
if (typeof data.actor !== "number") {
|
|
1064
|
+
throw new Error(`Authentication error. Liveblocks could not parse the response of your authentication endpoint`);
|
|
1065
|
+
}
|
|
1066
|
+
return data;
|
|
1067
|
+
}
|
|
1068
|
+
function prepareCreateWebSocket(liveblocksServer, WebSocketPolyfill) {
|
|
1069
|
+
if (typeof window === "undefined" && WebSocketPolyfill == null) {
|
|
1070
|
+
throw new Error("To use Liveblocks client in a non-dom environment, you need to provide a WebSocket polyfill.");
|
|
1071
|
+
}
|
|
1072
|
+
const ws = WebSocketPolyfill || WebSocket;
|
|
1073
|
+
return (token) => {
|
|
1074
|
+
return new ws(`${liveblocksServer}/?token=${token}`);
|
|
1075
|
+
};
|
|
1076
|
+
}
|
|
1077
|
+
function prepareAuthEndpoint(authentication, fetchPolyfill) {
|
|
1078
|
+
if (authentication.type === "public") {
|
|
1079
|
+
if (typeof window === "undefined" && fetchPolyfill == null) {
|
|
1080
|
+
throw new Error("To use Liveblocks client in a non-dom environment with a publicApiKey, you need to provide a fetch polyfill.");
|
|
1081
|
+
}
|
|
1082
|
+
return (room) => fetchAuthEndpoint(fetchPolyfill || fetch, authentication.url, {
|
|
1083
|
+
room,
|
|
1084
|
+
publicApiKey: authentication.publicApiKey,
|
|
1085
|
+
});
|
|
1086
|
+
}
|
|
1087
|
+
if (authentication.type === "private") {
|
|
1088
|
+
if (typeof window === "undefined" && fetchPolyfill == null) {
|
|
1089
|
+
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.");
|
|
1090
|
+
}
|
|
1091
|
+
return (room) => fetchAuthEndpoint(fetchPolyfill || fetch, authentication.url, {
|
|
1092
|
+
room,
|
|
1093
|
+
});
|
|
1094
|
+
}
|
|
1095
|
+
if (authentication.type === "custom") {
|
|
1096
|
+
return authentication.callback;
|
|
1097
|
+
}
|
|
1098
|
+
throw new Error("Internal error. Unexpected authentication type");
|
|
1099
|
+
}
|
|
1100
|
+
function fetchAuthEndpoint(fetch, endpoint, body) {
|
|
1101
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
1102
|
+
const res = yield fetch(endpoint, {
|
|
1103
|
+
method: "POST",
|
|
1104
|
+
headers: {
|
|
1105
|
+
"Content-Type": "application/json",
|
|
1106
|
+
},
|
|
1107
|
+
body: JSON.stringify(body),
|
|
1108
|
+
});
|
|
1109
|
+
if (!res.ok) {
|
|
1110
|
+
throw new AuthenticationError(`Authentication error. Liveblocks could not parse the response of your authentication "${endpoint}"`);
|
|
1111
|
+
}
|
|
1112
|
+
let authResponse = null;
|
|
1113
|
+
try {
|
|
1114
|
+
authResponse = yield res.json();
|
|
1115
|
+
}
|
|
1116
|
+
catch (er) {
|
|
1117
|
+
throw new AuthenticationError(`Authentication error. Liveblocks could not parse the response of your authentication "${endpoint}"`);
|
|
1118
|
+
}
|
|
1119
|
+
if (typeof authResponse.token !== "string") {
|
|
1120
|
+
throw new AuthenticationError(`Authentication error. Liveblocks could not parse the response of your authentication "${endpoint}"`);
|
|
1121
|
+
}
|
|
1122
|
+
return authResponse;
|
|
1123
|
+
});
|
|
1124
|
+
}
|
|
1125
|
+
class AuthenticationError extends Error {
|
|
1126
|
+
constructor(message) {
|
|
1127
|
+
super(message);
|
|
1128
|
+
}
|
|
1129
|
+
}
|
package/lib/cjs/types.d.ts
CHANGED
|
@@ -146,6 +146,8 @@ export declare type AuthEndpoint = string | AuthEndpointCallback;
|
|
|
146
146
|
*/
|
|
147
147
|
export declare type ClientOptions = {
|
|
148
148
|
throttle?: number;
|
|
149
|
+
fetchPolyfill?: any;
|
|
150
|
+
WebSocketPolyfill?: any;
|
|
149
151
|
} & ({
|
|
150
152
|
publicApiKey: string;
|
|
151
153
|
authEndpoint?: never;
|
|
@@ -156,6 +158,17 @@ export declare type ClientOptions = {
|
|
|
156
158
|
export declare type AuthorizeResponse = {
|
|
157
159
|
token: string;
|
|
158
160
|
};
|
|
161
|
+
export declare type Authentication = {
|
|
162
|
+
type: "public";
|
|
163
|
+
publicApiKey: string;
|
|
164
|
+
url: string;
|
|
165
|
+
} | {
|
|
166
|
+
type: "private";
|
|
167
|
+
url: string;
|
|
168
|
+
} | {
|
|
169
|
+
type: "custom";
|
|
170
|
+
callback: (room: string) => Promise<AuthorizeResponse>;
|
|
171
|
+
};
|
|
159
172
|
declare type ConnectionState = "closed" | "authenticating" | "unavailable" | "failed" | "open" | "connecting";
|
|
160
173
|
export declare type Connection = {
|
|
161
174
|
state: "closed" | "authenticating" | "unavailable" | "failed";
|
package/lib/cjs/utils.d.ts
CHANGED
|
@@ -9,3 +9,7 @@ export declare function selfOrRegisterValue(obj: AbstractCrdt): any;
|
|
|
9
9
|
export declare function selfOrRegister(obj: any): AbstractCrdt;
|
|
10
10
|
export declare function getTreesDiffOperations(currentItems: Map<string, SerializedCrdt>, newItems: Map<string, SerializedCrdt>): Op[];
|
|
11
11
|
export declare function mergeStorageUpdates(first: StorageUpdate | undefined, second: StorageUpdate): StorageUpdate;
|
|
12
|
+
export declare function findNonSerializableValue(value: any, path?: string): {
|
|
13
|
+
path: string;
|
|
14
|
+
value: any;
|
|
15
|
+
} | false;
|