@liveblocks/core 1.0.8 → 1.0.9
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/dist/index.d.ts +66 -59
- package/dist/index.js +124 -82
- package/package.json +1 -1
package/dist/index.d.ts
CHANGED
|
@@ -129,6 +129,63 @@ declare type UpdateDelta = {
|
|
|
129
129
|
type: "delete";
|
|
130
130
|
};
|
|
131
131
|
|
|
132
|
+
/**
|
|
133
|
+
* "Plain LSON" is a JSON-based format that's used when serializing Live structures
|
|
134
|
+
* to send them over HTTP (e.g. in the API endpoint to let users upload their initial
|
|
135
|
+
* Room storage, in the API endpoint to fetch a Room's storage, ...).
|
|
136
|
+
*
|
|
137
|
+
* In the client, you would typically create LSON values using:
|
|
138
|
+
*
|
|
139
|
+
* new LiveObject({ x: 0, y: 0 })
|
|
140
|
+
*
|
|
141
|
+
* But over HTTP, this has to be serialized somehow. The "Plain LSON" format
|
|
142
|
+
* is what's used in the POST /init-storage-new endpoint, to allow users to
|
|
143
|
+
* control which parts of their data structure should be considered "Live"
|
|
144
|
+
* objects, and which parts are "normal" objects.
|
|
145
|
+
*
|
|
146
|
+
* So if they have a structure like:
|
|
147
|
+
*
|
|
148
|
+
* { x: 0, y: 0 }
|
|
149
|
+
*
|
|
150
|
+
* And want to make it a Live object, they can serialize it by wrapping it in
|
|
151
|
+
* a special "annotation":
|
|
152
|
+
*
|
|
153
|
+
* {
|
|
154
|
+
* "liveblocksType": "LiveObject",
|
|
155
|
+
* "data": { x: 0, y: 0 },
|
|
156
|
+
* }
|
|
157
|
+
*
|
|
158
|
+
* This "Plain LSON" data format defines exactly those wrappings.
|
|
159
|
+
*
|
|
160
|
+
* To summarize:
|
|
161
|
+
*
|
|
162
|
+
* LSON value | Plain LSON equivalent
|
|
163
|
+
* ----------------------+----------------------------------------------
|
|
164
|
+
* 42 | 42
|
|
165
|
+
* [1, 2, 3] | [1, 2, 3]
|
|
166
|
+
* { x: 0, y: 0 } | { x: 0, y: 0 }
|
|
167
|
+
* ----------------------+----------------------------------------------
|
|
168
|
+
* new LiveList(...) | { liveblocksType: "LiveList", data: ... }
|
|
169
|
+
* new LiveMap(...) | { liveblocksType: "LiveMap", data: ... }
|
|
170
|
+
* new LiveObject(...) | { liveblocksType: "LiveObject", data: ... }
|
|
171
|
+
*
|
|
172
|
+
*/
|
|
173
|
+
|
|
174
|
+
declare type PlainLsonFields = Record<string, PlainLson>;
|
|
175
|
+
declare type PlainLsonObject = {
|
|
176
|
+
liveblocksType: "LiveObject";
|
|
177
|
+
data: PlainLsonFields;
|
|
178
|
+
};
|
|
179
|
+
declare type PlainLsonMap = {
|
|
180
|
+
liveblocksType: "LiveMap";
|
|
181
|
+
data: PlainLsonFields;
|
|
182
|
+
};
|
|
183
|
+
declare type PlainLsonList = {
|
|
184
|
+
liveblocksType: "LiveList";
|
|
185
|
+
data: PlainLson[];
|
|
186
|
+
};
|
|
187
|
+
declare type PlainLson = PlainLsonObject | PlainLsonMap | PlainLsonList | Json;
|
|
188
|
+
|
|
132
189
|
declare type LiveObjectUpdateDelta<O extends {
|
|
133
190
|
[key: string]: unknown;
|
|
134
191
|
}> = {
|
|
@@ -197,6 +254,10 @@ declare class LiveObject<O extends LsonObject> extends AbstractCrdt {
|
|
|
197
254
|
declare type ToImmutable<L extends Lson | LsonObject> = L extends LiveList<infer I> ? readonly ToImmutable<I>[] : L extends LiveObject<infer O> ? ToImmutable<O> : L extends LiveMap<infer K, infer V> ? ReadonlyMap<K, ToImmutable<V>> : L extends LsonObject ? {
|
|
198
255
|
readonly [K in keyof L]: ToImmutable<Exclude<L[K], undefined>> | (undefined extends L[K] ? undefined : never);
|
|
199
256
|
} : L extends Json ? L : never;
|
|
257
|
+
/**
|
|
258
|
+
* Returns PlainLson for a given Json or LiveStructure, suitable for calling the storage init api
|
|
259
|
+
*/
|
|
260
|
+
declare function toPlainLson(lson: Lson): PlainLson;
|
|
200
261
|
|
|
201
262
|
/**
|
|
202
263
|
* A LiveMap notification that is sent in-client to any subscribers whenever
|
|
@@ -268,12 +329,15 @@ declare class LiveMap<TKey extends string, TValue extends Lson> extends Abstract
|
|
|
268
329
|
}
|
|
269
330
|
|
|
270
331
|
declare type StorageCallback = (updates: StorageUpdate[]) => void;
|
|
332
|
+
declare type LiveMapUpdate = LiveMapUpdates<string, Lson>;
|
|
333
|
+
declare type LiveObjectUpdate = LiveObjectUpdates<LsonObject>;
|
|
334
|
+
declare type LiveListUpdate = LiveListUpdates<Lson>;
|
|
271
335
|
/**
|
|
272
336
|
* The payload of notifications sent (in-client) when LiveStructures change.
|
|
273
337
|
* Messages of this kind are not originating from the network, but are 100%
|
|
274
338
|
* in-client.
|
|
275
339
|
*/
|
|
276
|
-
declare type StorageUpdate =
|
|
340
|
+
declare type StorageUpdate = LiveMapUpdate | LiveObjectUpdate | LiveListUpdate;
|
|
277
341
|
|
|
278
342
|
declare abstract class AbstractCrdt {
|
|
279
343
|
get roomId(): string | null;
|
|
@@ -1546,63 +1610,6 @@ SerializedCrdt>;
|
|
|
1546
1610
|
declare type ParentToChildNodeMap = Map<string, // Parent's node ID
|
|
1547
1611
|
IdTuple<SerializedChild>[]>;
|
|
1548
1612
|
|
|
1549
|
-
/**
|
|
1550
|
-
* "Plain LSON" is a JSON-based format that's used when serializing Live structures
|
|
1551
|
-
* to send them over HTTP (e.g. in the API endpoint to let users upload their initial
|
|
1552
|
-
* Room storage, in the API endpoint to fetch a Room's storage, ...).
|
|
1553
|
-
*
|
|
1554
|
-
* In the client, you would typically create LSON values using:
|
|
1555
|
-
*
|
|
1556
|
-
* new LiveObject({ x: 0, y: 0 })
|
|
1557
|
-
*
|
|
1558
|
-
* But over HTTP, this has to be serialized somehow. The "Plain LSON" format
|
|
1559
|
-
* is what's used in the POST /init-storage-new endpoint, to allow users to
|
|
1560
|
-
* control which parts of their data structure should be considered "Live"
|
|
1561
|
-
* objects, and which parts are "normal" objects.
|
|
1562
|
-
*
|
|
1563
|
-
* So if they have a structure like:
|
|
1564
|
-
*
|
|
1565
|
-
* { x: 0, y: 0 }
|
|
1566
|
-
*
|
|
1567
|
-
* And want to make it a Live object, they can serialize it by wrapping it in
|
|
1568
|
-
* a special "annotation":
|
|
1569
|
-
*
|
|
1570
|
-
* {
|
|
1571
|
-
* "liveblocksType": "LiveObject",
|
|
1572
|
-
* "data": { x: 0, y: 0 },
|
|
1573
|
-
* }
|
|
1574
|
-
*
|
|
1575
|
-
* This "Plain LSON" data format defines exactly those wrappings.
|
|
1576
|
-
*
|
|
1577
|
-
* To summarize:
|
|
1578
|
-
*
|
|
1579
|
-
* LSON value | Plain LSON equivalent
|
|
1580
|
-
* ----------------------+----------------------------------------------
|
|
1581
|
-
* 42 | 42
|
|
1582
|
-
* [1, 2, 3] | [1, 2, 3]
|
|
1583
|
-
* { x: 0, y: 0 } | { x: 0, y: 0 }
|
|
1584
|
-
* ----------------------+----------------------------------------------
|
|
1585
|
-
* new LiveList(...) | { liveblocksType: "LiveList", data: ... }
|
|
1586
|
-
* new LiveMap(...) | { liveblocksType: "LiveMap", data: ... }
|
|
1587
|
-
* new LiveObject(...) | { liveblocksType: "LiveObject", data: ... }
|
|
1588
|
-
*
|
|
1589
|
-
*/
|
|
1590
|
-
|
|
1591
|
-
declare type PlainLsonFields = Record<string, PlainLson>;
|
|
1592
|
-
declare type PlainLsonObject = {
|
|
1593
|
-
liveblocksType: "LiveObject";
|
|
1594
|
-
data: PlainLsonFields;
|
|
1595
|
-
};
|
|
1596
|
-
declare type PlainLsonMap = {
|
|
1597
|
-
liveblocksType: "LiveMap";
|
|
1598
|
-
data: PlainLsonFields;
|
|
1599
|
-
};
|
|
1600
|
-
declare type PlainLsonList = {
|
|
1601
|
-
liveblocksType: "LiveList";
|
|
1602
|
-
data: PlainLson[];
|
|
1603
|
-
};
|
|
1604
|
-
declare type PlainLson = PlainLsonObject | PlainLsonMap | PlainLsonList | Json;
|
|
1605
|
-
|
|
1606
1613
|
declare type JsonTreeNode = {
|
|
1607
1614
|
readonly type: "Json";
|
|
1608
1615
|
readonly id: string;
|
|
@@ -1779,4 +1786,4 @@ declare type EnsureJson<T> = [
|
|
|
1779
1786
|
[K in keyof T]: EnsureJson<T[K]>;
|
|
1780
1787
|
};
|
|
1781
1788
|
|
|
1782
|
-
export { AckOp, AppOnlyAuthToken, AuthToken, BaseUserMeta, BroadcastEventClientMsg, BroadcastOptions, BroadcastedEventServerMsg, Client, ClientMsg, ClientMsgCode, ConnectionStatus, CrdtType, CreateChildOp, CreateListOp, CreateMapOp, CreateObjectOp, CreateOp, CreateRegisterOp, CreateRootObjectOp, DeleteCrdtOp, DeleteObjectKeyOp, DevToolsTreeNode as DevTools, protocol as DevToolsMsg, EnsureJson, FetchStorageClientMsg, History, IWebSocket, IWebSocketCloseEvent, IWebSocketEvent, IWebSocketInstance, IWebSocketMessageEvent, IdTuple, Immutable, InitialDocumentStateServerMsg, Json, JsonArray, JsonObject, JsonScalar, LiveList, LiveMap, LiveNode, LiveObject, LiveStructure, Lson, LsonObject, NodeMap, Op, OpCode, Others, ParentToChildNodeMap, PlainLson, PlainLsonFields, PlainLsonList, PlainLsonMap, PlainLsonObject, RejectedStorageOpServerMsg, Resolve, Room, RoomAuthToken, RoomInitializers, RoomStateServerMsg, SerializedChild, SerializedCrdt, SerializedList, SerializedMap, SerializedObject, SerializedRegister, SerializedRootObject, ServerMsg, ServerMsgCode, SetParentKeyOp, StorageStatus, StorageUpdate, ToImmutable, ToJson, UpdateObjectOp, UpdatePresenceClientMsg, UpdatePresenceServerMsg, UpdateStorageClientMsg, UpdateStorageServerMsg, User, UserJoinServerMsg, UserLeftServerMsg, WebsocketCloseCodes, asArrayWithLegacyMethods, asPos, assert, assertNever, b64decode, createClient, deprecate, deprecateIf, errorIf, freeze, isAppOnlyAuthToken, isAuthToken, isChildCrdt, isJsonArray, isJsonObject, isJsonScalar, isPlainObject, isRoomAuthToken, isRootCrdt, legacy_patchImmutableObject, lsonToJson, makePosition, nn, patchLiveObjectKey, shallow, throwUsageError, tryParseJson };
|
|
1789
|
+
export { AckOp, AppOnlyAuthToken, AuthToken, BaseUserMeta, BroadcastEventClientMsg, BroadcastOptions, BroadcastedEventServerMsg, Client, ClientMsg, ClientMsgCode, ConnectionStatus, CrdtType, CreateChildOp, CreateListOp, CreateMapOp, CreateObjectOp, CreateOp, CreateRegisterOp, CreateRootObjectOp, DeleteCrdtOp, DeleteObjectKeyOp, DevToolsTreeNode as DevTools, protocol as DevToolsMsg, EnsureJson, FetchStorageClientMsg, History, IWebSocket, IWebSocketCloseEvent, IWebSocketEvent, IWebSocketInstance, IWebSocketMessageEvent, IdTuple, Immutable, InitialDocumentStateServerMsg, Json, JsonArray, JsonObject, JsonScalar, LiveList, LiveListUpdate, LiveMap, LiveMapUpdate, LiveNode, LiveObject, LiveObjectUpdate, LiveStructure, Lson, LsonObject, NodeMap, Op, OpCode, Others, ParentToChildNodeMap, PlainLson, PlainLsonFields, PlainLsonList, PlainLsonMap, PlainLsonObject, RejectedStorageOpServerMsg, Resolve, Room, RoomAuthToken, RoomInitializers, RoomStateServerMsg, SerializedChild, SerializedCrdt, SerializedList, SerializedMap, SerializedObject, SerializedRegister, SerializedRootObject, ServerMsg, ServerMsgCode, SetParentKeyOp, StorageStatus, StorageUpdate, ToImmutable, ToJson, UpdateObjectOp, UpdatePresenceClientMsg, UpdatePresenceServerMsg, UpdateStorageClientMsg, UpdateStorageServerMsg, User, UserJoinServerMsg, UserLeftServerMsg, WebsocketCloseCodes, asArrayWithLegacyMethods, asPos, assert, assertNever, b64decode, createClient, deprecate, deprecateIf, errorIf, freeze, isAppOnlyAuthToken, isAuthToken, isChildCrdt, isJsonArray, isJsonObject, isJsonScalar, isPlainObject, isRoomAuthToken, isRootCrdt, legacy_patchImmutableObject, lsonToJson, makePosition, nn, patchLiveObjectKey, shallow, throwUsageError, toPlainLson, tryParseJson };
|
package/dist/index.js
CHANGED
|
@@ -117,7 +117,7 @@ var onMessageFromPanel = eventSource.observable;
|
|
|
117
117
|
// src/devtools/index.ts
|
|
118
118
|
var VERSION = true ? (
|
|
119
119
|
/* istanbul ignore next */
|
|
120
|
-
"1.0.
|
|
120
|
+
"1.0.9"
|
|
121
121
|
) : "dev";
|
|
122
122
|
var _devtoolsSetupHasRun = false;
|
|
123
123
|
function setupDevTools(getAllRooms) {
|
|
@@ -2983,20 +2983,22 @@ function parseJwtToken(token) {
|
|
|
2983
2983
|
}
|
|
2984
2984
|
function parseRoomAuthToken(tokenString) {
|
|
2985
2985
|
const data = parseJwtToken(tokenString);
|
|
2986
|
-
if (data && isRoomAuthToken(data)) {
|
|
2987
|
-
const _a = data, {
|
|
2988
|
-
maxConnections: _legacyField
|
|
2989
|
-
} = _a, token = __objRest(_a, [
|
|
2990
|
-
// If this legacy field is found on the token, pretend it wasn't there,
|
|
2991
|
-
// to make all internally used token payloads uniform
|
|
2992
|
-
"maxConnections"
|
|
2993
|
-
]);
|
|
2994
|
-
return token;
|
|
2995
|
-
} else {
|
|
2986
|
+
if (!(data && isRoomAuthToken(data))) {
|
|
2996
2987
|
throw new Error(
|
|
2997
2988
|
"Authentication error: we expected a room token but did not get one. Hint: if you are using a callback, ensure the room is passed when creating the token. For more information: https://liveblocks.io/docs/api-reference/liveblocks-client#createClientCallback"
|
|
2998
2989
|
);
|
|
2999
2990
|
}
|
|
2991
|
+
const _a = data, {
|
|
2992
|
+
maxConnections: _legacyField
|
|
2993
|
+
} = _a, parsedToken = __objRest(_a, [
|
|
2994
|
+
// If this legacy field is found on the token, pretend it wasn't there,
|
|
2995
|
+
// to make all internally used token payloads uniform
|
|
2996
|
+
"maxConnections"
|
|
2997
|
+
]);
|
|
2998
|
+
return {
|
|
2999
|
+
raw: tokenString,
|
|
3000
|
+
parsed: parsedToken
|
|
3001
|
+
};
|
|
3000
3002
|
}
|
|
3001
3003
|
|
|
3002
3004
|
// src/protocol/ClientMsg.ts
|
|
@@ -3380,21 +3382,20 @@ function createRoom(options, config) {
|
|
|
3380
3382
|
storageStatus: makeEventSource()
|
|
3381
3383
|
};
|
|
3382
3384
|
const effects = config.mockedEffects || {
|
|
3383
|
-
|
|
3385
|
+
authenticateAndConnect(auth, createWebSocket) {
|
|
3384
3386
|
const prevToken = context.token;
|
|
3385
3387
|
if (prevToken !== null && !isTokenExpired(prevToken.parsed)) {
|
|
3386
|
-
const socket = createWebSocket(prevToken
|
|
3387
|
-
|
|
3388
|
+
const socket = createWebSocket(prevToken);
|
|
3389
|
+
handleAuthSuccess(prevToken.parsed, socket);
|
|
3388
3390
|
return void 0;
|
|
3389
3391
|
} else {
|
|
3390
|
-
void auth(
|
|
3392
|
+
void auth().then((token) => {
|
|
3391
3393
|
if (context.connection.current.status !== "authenticating") {
|
|
3392
3394
|
return;
|
|
3393
3395
|
}
|
|
3394
|
-
const parsedToken = parseRoomAuthToken(token);
|
|
3395
3396
|
const socket = createWebSocket(token);
|
|
3396
|
-
|
|
3397
|
-
context.token =
|
|
3397
|
+
handleAuthSuccess(token.parsed, socket);
|
|
3398
|
+
context.token = token;
|
|
3398
3399
|
}).catch(
|
|
3399
3400
|
(er) => authenticationFailure(
|
|
3400
3401
|
er instanceof Error ? er : new Error(String(er))
|
|
@@ -3412,7 +3413,7 @@ function createRoom(options, config) {
|
|
|
3412
3413
|
}
|
|
3413
3414
|
},
|
|
3414
3415
|
scheduleFlush: (delay) => setTimeout(tryFlushing, delay),
|
|
3415
|
-
scheduleReconnect: (delay) => setTimeout(
|
|
3416
|
+
scheduleReconnect: (delay) => setTimeout(handleConnect, delay),
|
|
3416
3417
|
startHeartbeatInterval: () => setInterval(heartbeat, HEARTBEAT_INTERVAL),
|
|
3417
3418
|
schedulePongTimeout: () => setTimeout(pongTimeout, PONG_TIMEOUT)
|
|
3418
3419
|
};
|
|
@@ -3621,12 +3622,13 @@ function createRoom(options, config) {
|
|
|
3621
3622
|
}
|
|
3622
3623
|
}
|
|
3623
3624
|
}
|
|
3624
|
-
function
|
|
3625
|
+
function handleConnect() {
|
|
3625
3626
|
var _a2, _b;
|
|
3626
3627
|
if (context.connection.current.status !== "closed" && context.connection.current.status !== "unavailable") {
|
|
3627
3628
|
return;
|
|
3628
3629
|
}
|
|
3629
3630
|
const auth = prepareAuthEndpoint(
|
|
3631
|
+
config.roomId,
|
|
3630
3632
|
config.authentication,
|
|
3631
3633
|
(_a2 = config.polyfills) == null ? void 0 : _a2.fetch
|
|
3632
3634
|
);
|
|
@@ -3635,7 +3637,7 @@ function createRoom(options, config) {
|
|
|
3635
3637
|
(_b = config.polyfills) == null ? void 0 : _b.WebSocket
|
|
3636
3638
|
);
|
|
3637
3639
|
updateConnection({ status: "authenticating" }, batchUpdates);
|
|
3638
|
-
effects.
|
|
3640
|
+
effects.authenticateAndConnect(auth, createWebSocket);
|
|
3639
3641
|
}
|
|
3640
3642
|
function updatePresence(patch, options2) {
|
|
3641
3643
|
const oldValues = {};
|
|
@@ -3678,11 +3680,11 @@ function createRoom(options, config) {
|
|
|
3678
3680
|
function isStorageReadOnly(scopes) {
|
|
3679
3681
|
return scopes.includes("room:read" /* Read */) && scopes.includes("room:presence:write" /* PresenceWrite */) && !scopes.includes("room:write" /* Write */);
|
|
3680
3682
|
}
|
|
3681
|
-
function
|
|
3682
|
-
socket.addEventListener("message",
|
|
3683
|
-
socket.addEventListener("open",
|
|
3684
|
-
socket.addEventListener("close",
|
|
3685
|
-
socket.addEventListener("error",
|
|
3683
|
+
function handleAuthSuccess(token, socket) {
|
|
3684
|
+
socket.addEventListener("message", handleRawSocketMessage);
|
|
3685
|
+
socket.addEventListener("open", handleSocketOpen);
|
|
3686
|
+
socket.addEventListener("close", handleExplicitClose);
|
|
3687
|
+
socket.addEventListener("error", handleSocketError);
|
|
3686
3688
|
updateConnection(
|
|
3687
3689
|
{
|
|
3688
3690
|
status: "connecting",
|
|
@@ -3706,8 +3708,8 @@ function createRoom(options, config) {
|
|
|
3706
3708
|
clearTimeout(context.timers.reconnect);
|
|
3707
3709
|
context.timers.reconnect = effects.scheduleReconnect(getRetryDelay());
|
|
3708
3710
|
}
|
|
3709
|
-
function
|
|
3710
|
-
if (
|
|
3711
|
+
function handleWindowGotFocus() {
|
|
3712
|
+
if (context.connection.current.status === "open") {
|
|
3711
3713
|
log("Heartbeat after visibility change");
|
|
3712
3714
|
heartbeat();
|
|
3713
3715
|
}
|
|
@@ -3761,7 +3763,7 @@ function createRoom(options, config) {
|
|
|
3761
3763
|
}
|
|
3762
3764
|
return { type: "reset" };
|
|
3763
3765
|
}
|
|
3764
|
-
function
|
|
3766
|
+
function handleNavigatorBackOnline() {
|
|
3765
3767
|
if (context.connection.current.status === "unavailable") {
|
|
3766
3768
|
log("Try to reconnect after connectivity change");
|
|
3767
3769
|
reconnect();
|
|
@@ -3824,11 +3826,17 @@ function createRoom(options, config) {
|
|
|
3824
3826
|
notify(result.updates, batchedUpdatesWrapper);
|
|
3825
3827
|
effects.send(messages);
|
|
3826
3828
|
}
|
|
3827
|
-
function
|
|
3829
|
+
function handleRawSocketMessage(event) {
|
|
3828
3830
|
if (event.data === "pong") {
|
|
3829
|
-
|
|
3830
|
-
|
|
3831
|
+
transition({ type: "RECEIVE_PONG" });
|
|
3832
|
+
} else {
|
|
3833
|
+
handleServerMessage(event);
|
|
3831
3834
|
}
|
|
3835
|
+
}
|
|
3836
|
+
function handlePong() {
|
|
3837
|
+
clearTimeout(context.timers.pongTimeout);
|
|
3838
|
+
}
|
|
3839
|
+
function handleServerMessage(event) {
|
|
3832
3840
|
if (typeof event.data !== "string") {
|
|
3833
3841
|
return;
|
|
3834
3842
|
}
|
|
@@ -3929,7 +3937,7 @@ ${Array.from(traces).join("\n\n")}`
|
|
|
3929
3937
|
notify(updates, doNotBatchUpdates);
|
|
3930
3938
|
});
|
|
3931
3939
|
}
|
|
3932
|
-
function
|
|
3940
|
+
function handleExplicitClose(event) {
|
|
3933
3941
|
context.socket = null;
|
|
3934
3942
|
clearTimeout(context.timers.flush);
|
|
3935
3943
|
clearTimeout(context.timers.reconnect);
|
|
@@ -3980,9 +3988,9 @@ ${Array.from(traces).join("\n\n")}`
|
|
|
3980
3988
|
}
|
|
3981
3989
|
return BACKOFF_RETRY_DELAYS[context.numRetries < BACKOFF_RETRY_DELAYS.length ? context.numRetries : BACKOFF_RETRY_DELAYS.length - 1];
|
|
3982
3990
|
}
|
|
3983
|
-
function
|
|
3991
|
+
function handleSocketError() {
|
|
3984
3992
|
}
|
|
3985
|
-
function
|
|
3993
|
+
function handleSocketOpen() {
|
|
3986
3994
|
clearInterval(context.timers.heartbeat);
|
|
3987
3995
|
context.timers.heartbeat = effects.startHeartbeatInterval();
|
|
3988
3996
|
if (context.connection.current.status === "connecting") {
|
|
@@ -4025,12 +4033,12 @@ ${Array.from(traces).join("\n\n")}`
|
|
|
4025
4033
|
log("Pong timeout. Trying to reconnect.");
|
|
4026
4034
|
reconnect();
|
|
4027
4035
|
}
|
|
4028
|
-
function
|
|
4036
|
+
function handleDisconnect() {
|
|
4029
4037
|
if (context.socket) {
|
|
4030
|
-
context.socket.removeEventListener("open",
|
|
4031
|
-
context.socket.removeEventListener("message",
|
|
4032
|
-
context.socket.removeEventListener("close",
|
|
4033
|
-
context.socket.removeEventListener("error",
|
|
4038
|
+
context.socket.removeEventListener("open", handleSocketOpen);
|
|
4039
|
+
context.socket.removeEventListener("message", handleRawSocketMessage);
|
|
4040
|
+
context.socket.removeEventListener("close", handleExplicitClose);
|
|
4041
|
+
context.socket.removeEventListener("error", handleSocketError);
|
|
4034
4042
|
context.socket.close();
|
|
4035
4043
|
context.socket = null;
|
|
4036
4044
|
}
|
|
@@ -4049,10 +4057,10 @@ ${Array.from(traces).join("\n\n")}`
|
|
|
4049
4057
|
}
|
|
4050
4058
|
function reconnect() {
|
|
4051
4059
|
if (context.socket) {
|
|
4052
|
-
context.socket.removeEventListener("open",
|
|
4053
|
-
context.socket.removeEventListener("message",
|
|
4054
|
-
context.socket.removeEventListener("close",
|
|
4055
|
-
context.socket.removeEventListener("error",
|
|
4060
|
+
context.socket.removeEventListener("open", handleSocketOpen);
|
|
4061
|
+
context.socket.removeEventListener("message", handleRawSocketMessage);
|
|
4062
|
+
context.socket.removeEventListener("close", handleExplicitClose);
|
|
4063
|
+
context.socket.removeEventListener("error", handleSocketError);
|
|
4056
4064
|
context.socket.close();
|
|
4057
4065
|
context.socket = null;
|
|
4058
4066
|
}
|
|
@@ -4061,7 +4069,7 @@ ${Array.from(traces).join("\n\n")}`
|
|
|
4061
4069
|
clearInterval(context.timers.heartbeat);
|
|
4062
4070
|
clearTimeout(context.timers.pongTimeout);
|
|
4063
4071
|
updateConnection({ status: "unavailable" }, batchUpdates);
|
|
4064
|
-
|
|
4072
|
+
handleConnect();
|
|
4065
4073
|
}
|
|
4066
4074
|
function tryFlushing() {
|
|
4067
4075
|
const storageOps = context.buffer.storageOperations;
|
|
@@ -4264,14 +4272,11 @@ ${Array.from(traces).join("\n\n")}`
|
|
|
4264
4272
|
_addToRealUndoStack(historyOps, batchUpdates);
|
|
4265
4273
|
}
|
|
4266
4274
|
}
|
|
4267
|
-
function
|
|
4275
|
+
function handleImplicitClose() {
|
|
4268
4276
|
if (context.socket) {
|
|
4269
4277
|
context.socket = null;
|
|
4270
4278
|
}
|
|
4271
4279
|
}
|
|
4272
|
-
function simulateSendCloseEvent(event) {
|
|
4273
|
-
onClose(event);
|
|
4274
|
-
}
|
|
4275
4280
|
function getStorageStatus() {
|
|
4276
4281
|
if (_getInitialStatePromise === null) {
|
|
4277
4282
|
return "not-loaded";
|
|
@@ -4304,6 +4309,28 @@ ${Array.from(traces).join("\n\n")}`
|
|
|
4304
4309
|
storageDidLoad: eventHub.storageDidLoad.observable,
|
|
4305
4310
|
storageStatus: eventHub.storageStatus.observable
|
|
4306
4311
|
};
|
|
4312
|
+
function transition(event) {
|
|
4313
|
+
switch (event.type) {
|
|
4314
|
+
case "CONNECT":
|
|
4315
|
+
return handleConnect();
|
|
4316
|
+
case "DISCONNECT":
|
|
4317
|
+
return handleDisconnect();
|
|
4318
|
+
case "RECEIVE_PONG":
|
|
4319
|
+
return handlePong();
|
|
4320
|
+
case "AUTH_SUCCESS":
|
|
4321
|
+
return handleAuthSuccess(event.token, event.socket);
|
|
4322
|
+
case "WINDOW_GOT_FOCUS":
|
|
4323
|
+
return handleWindowGotFocus();
|
|
4324
|
+
case "NAVIGATOR_ONLINE":
|
|
4325
|
+
return handleNavigatorBackOnline();
|
|
4326
|
+
case "IMPLICIT_CLOSE":
|
|
4327
|
+
return handleImplicitClose();
|
|
4328
|
+
case "EXPLICIT_CLOSE":
|
|
4329
|
+
return handleExplicitClose(event.closeEvent);
|
|
4330
|
+
default:
|
|
4331
|
+
return assertNever(event, "Invalid event");
|
|
4332
|
+
}
|
|
4333
|
+
}
|
|
4307
4334
|
return {
|
|
4308
4335
|
/* NOTE: Exposing __internal here only to allow testing implementation details in unit tests */
|
|
4309
4336
|
__internal: {
|
|
@@ -4315,20 +4342,36 @@ ${Array.from(traces).join("\n\n")}`
|
|
|
4315
4342
|
return context.numRetries;
|
|
4316
4343
|
},
|
|
4317
4344
|
// prettier-ignore
|
|
4318
|
-
|
|
4319
|
-
|
|
4320
|
-
|
|
4321
|
-
|
|
4322
|
-
|
|
4323
|
-
|
|
4324
|
-
|
|
4325
|
-
|
|
4326
|
-
getItemsCount: () => context.nodes.size,
|
|
4327
|
-
connect,
|
|
4328
|
-
disconnect,
|
|
4345
|
+
get undoStack() {
|
|
4346
|
+
return context.undoStack;
|
|
4347
|
+
},
|
|
4348
|
+
// prettier-ignore
|
|
4349
|
+
get nodeCount() {
|
|
4350
|
+
return context.nodes.size;
|
|
4351
|
+
},
|
|
4352
|
+
// prettier-ignore
|
|
4329
4353
|
// Support for the Liveblocks browser extension
|
|
4330
4354
|
getSelf_forDevTools: () => selfAsTreeNode.current,
|
|
4331
|
-
getOthers_forDevTools: () => others_forDevTools.current
|
|
4355
|
+
getOthers_forDevTools: () => others_forDevTools.current,
|
|
4356
|
+
// prettier-ignore
|
|
4357
|
+
send: {
|
|
4358
|
+
explicitClose: (closeEvent) => transition({ type: "EXPLICIT_CLOSE", closeEvent }),
|
|
4359
|
+
implicitClose: () => transition({ type: "IMPLICIT_CLOSE" }),
|
|
4360
|
+
authSuccess: (token, socket) => transition({ type: "AUTH_SUCCESS", token, socket }),
|
|
4361
|
+
navigatorOnline: () => transition({ type: "NAVIGATOR_ONLINE" }),
|
|
4362
|
+
windowGotFocus: () => transition({ type: "WINDOW_GOT_FOCUS" }),
|
|
4363
|
+
pong: () => transition({ type: "RECEIVE_PONG" }),
|
|
4364
|
+
connect: () => transition({ type: "CONNECT" }),
|
|
4365
|
+
disconnect: () => transition({ type: "DISCONNECT" }),
|
|
4366
|
+
/**
|
|
4367
|
+
* This one looks differently from the rest, because receiving messages
|
|
4368
|
+
* is handled orthorgonally from all other possible events above,
|
|
4369
|
+
* because it does not matter what the connectivity state of the
|
|
4370
|
+
* machine is, so there won't be an explicit state machine transition
|
|
4371
|
+
* needed for this event.
|
|
4372
|
+
*/
|
|
4373
|
+
incomingMessage: handleServerMessage
|
|
4374
|
+
}
|
|
4332
4375
|
},
|
|
4333
4376
|
id: config.roomId,
|
|
4334
4377
|
subscribe: makeClassicSubscribeFn(events),
|
|
@@ -4404,10 +4447,6 @@ function makeClassicSubscribeFn(events) {
|
|
|
4404
4447
|
return events.connection.subscribe(
|
|
4405
4448
|
callback
|
|
4406
4449
|
);
|
|
4407
|
-
case "storage":
|
|
4408
|
-
return events.storage.subscribe(
|
|
4409
|
-
callback
|
|
4410
|
-
);
|
|
4411
4450
|
case "history":
|
|
4412
4451
|
return events.history.subscribe(callback);
|
|
4413
4452
|
case "storage-status":
|
|
@@ -4456,34 +4495,35 @@ function prepareCreateWebSocket(liveblocksServer, WebSocketPolyfill) {
|
|
|
4456
4495
|
);
|
|
4457
4496
|
}
|
|
4458
4497
|
const ws = WebSocketPolyfill || WebSocket;
|
|
4459
|
-
return (
|
|
4498
|
+
return (richToken) => {
|
|
4499
|
+
const token = richToken.raw;
|
|
4460
4500
|
return new ws(
|
|
4461
4501
|
`${liveblocksServer}/?token=${token}&version=${// prettier-ignore
|
|
4462
4502
|
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
|
|
4463
4503
|
// @ts-ignore (__PACKAGE_VERSION__ will be injected by the build script)
|
|
4464
4504
|
true ? (
|
|
4465
4505
|
/* istanbul ignore next */
|
|
4466
|
-
"1.0.
|
|
4506
|
+
"1.0.9"
|
|
4467
4507
|
) : "dev"}`
|
|
4468
4508
|
);
|
|
4469
4509
|
};
|
|
4470
4510
|
}
|
|
4471
|
-
function prepareAuthEndpoint(authentication, fetchPolyfill) {
|
|
4511
|
+
function prepareAuthEndpoint(roomId, authentication, fetchPolyfill) {
|
|
4472
4512
|
if (authentication.type === "public") {
|
|
4473
4513
|
if (typeof window === "undefined" && fetchPolyfill === void 0) {
|
|
4474
4514
|
throw new Error(
|
|
4475
4515
|
"To use Liveblocks client in a non-dom environment with a publicApiKey, you need to provide a fetch polyfill."
|
|
4476
4516
|
);
|
|
4477
4517
|
}
|
|
4478
|
-
return (
|
|
4518
|
+
return () => fetchAuthEndpoint(
|
|
4479
4519
|
fetchPolyfill || /* istanbul ignore next */
|
|
4480
4520
|
fetch,
|
|
4481
4521
|
authentication.url,
|
|
4482
4522
|
{
|
|
4483
|
-
room,
|
|
4523
|
+
room: roomId,
|
|
4484
4524
|
publicApiKey: authentication.publicApiKey
|
|
4485
4525
|
}
|
|
4486
|
-
);
|
|
4526
|
+
).then(({ token }) => parseRoomAuthToken(token));
|
|
4487
4527
|
}
|
|
4488
4528
|
if (authentication.type === "private") {
|
|
4489
4529
|
if (typeof window === "undefined" && fetchPolyfill === void 0) {
|
|
@@ -4491,19 +4531,19 @@ function prepareAuthEndpoint(authentication, fetchPolyfill) {
|
|
|
4491
4531
|
"To use Liveblocks client in a non-dom environment with a url as auth endpoint, you need to provide a fetch polyfill."
|
|
4492
4532
|
);
|
|
4493
4533
|
}
|
|
4494
|
-
return (
|
|
4495
|
-
room
|
|
4496
|
-
});
|
|
4534
|
+
return () => fetchAuthEndpoint(fetchPolyfill || fetch, authentication.url, {
|
|
4535
|
+
room: roomId
|
|
4536
|
+
}).then(({ token }) => parseRoomAuthToken(token));
|
|
4497
4537
|
}
|
|
4498
4538
|
if (authentication.type === "custom") {
|
|
4499
|
-
return (
|
|
4500
|
-
const response = yield authentication.callback(
|
|
4539
|
+
return () => __async(this, null, function* () {
|
|
4540
|
+
const response = yield authentication.callback(roomId);
|
|
4501
4541
|
if (!response || !response.token) {
|
|
4502
4542
|
throw new Error(
|
|
4503
4543
|
'Authentication error. We expect the authentication callback to return a token, but it does not. Hint: the return value should look like: { token: "..." }'
|
|
4504
4544
|
);
|
|
4505
4545
|
}
|
|
4506
|
-
return response;
|
|
4546
|
+
return parseRoomAuthToken(response.token);
|
|
4507
4547
|
});
|
|
4508
4548
|
}
|
|
4509
4549
|
throw new Error("Internal error. Unexpected authentication type");
|
|
@@ -4604,7 +4644,7 @@ function createClient(options) {
|
|
|
4604
4644
|
}
|
|
4605
4645
|
global.atob = clientOptions.polyfills.atob;
|
|
4606
4646
|
}
|
|
4607
|
-
newRoom.__internal.connect();
|
|
4647
|
+
newRoom.__internal.send.connect();
|
|
4608
4648
|
}
|
|
4609
4649
|
return newRoom;
|
|
4610
4650
|
}
|
|
@@ -4612,7 +4652,7 @@ function createClient(options) {
|
|
|
4612
4652
|
unlinkDevTools(roomId);
|
|
4613
4653
|
const room = rooms.get(roomId);
|
|
4614
4654
|
if (room !== void 0) {
|
|
4615
|
-
room.__internal.disconnect();
|
|
4655
|
+
room.__internal.send.disconnect();
|
|
4616
4656
|
rooms.delete(roomId);
|
|
4617
4657
|
}
|
|
4618
4658
|
}
|
|
@@ -4620,14 +4660,16 @@ function createClient(options) {
|
|
|
4620
4660
|
typeof window.addEventListener !== "undefined") {
|
|
4621
4661
|
window.addEventListener("online", () => {
|
|
4622
4662
|
for (const [, room] of rooms) {
|
|
4623
|
-
room.__internal.
|
|
4663
|
+
room.__internal.send.navigatorOnline();
|
|
4624
4664
|
}
|
|
4625
4665
|
});
|
|
4626
4666
|
}
|
|
4627
4667
|
if (typeof document !== "undefined") {
|
|
4628
4668
|
document.addEventListener("visibilitychange", () => {
|
|
4629
|
-
|
|
4630
|
-
room
|
|
4669
|
+
if (document.visibilityState === "visible") {
|
|
4670
|
+
for (const [, room] of rooms) {
|
|
4671
|
+
room.__internal.send.windowGotFocus();
|
|
4672
|
+
}
|
|
4631
4673
|
}
|
|
4632
4674
|
});
|
|
4633
4675
|
}
|