@liveblocks/client 0.16.0 → 0.16.1
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/esm/index.js +65 -33
- package/lib/esm/index.mjs +65 -33
- package/lib/index.d.ts +17 -0
- package/lib/index.js +72 -32
- package/lib/internal.d.ts +81 -3
- package/package.json +1 -1
package/lib/esm/index.js
CHANGED
|
@@ -915,6 +915,20 @@ class LiveMap extends AbstractCrdt {
|
|
|
915
915
|
}
|
|
916
916
|
}
|
|
917
917
|
|
|
918
|
+
function parseJson(rawMessage) {
|
|
919
|
+
try {
|
|
920
|
+
return JSON.parse(rawMessage);
|
|
921
|
+
} catch (e) {
|
|
922
|
+
return void 0;
|
|
923
|
+
}
|
|
924
|
+
}
|
|
925
|
+
function isJsonArray(data) {
|
|
926
|
+
return Array.isArray(data);
|
|
927
|
+
}
|
|
928
|
+
function isJsonObject(data) {
|
|
929
|
+
return data !== null && typeof data === "object" && !isJsonArray(data);
|
|
930
|
+
}
|
|
931
|
+
|
|
918
932
|
var __defProp$2 = Object.defineProperty;
|
|
919
933
|
var __defProps$2 = Object.defineProperties;
|
|
920
934
|
var __getOwnPropDescs$2 = Object.getOwnPropertyDescriptors;
|
|
@@ -942,6 +956,9 @@ function remove(array, item) {
|
|
|
942
956
|
}
|
|
943
957
|
}
|
|
944
958
|
}
|
|
959
|
+
function compact(items) {
|
|
960
|
+
return items.filter((item) => item != null);
|
|
961
|
+
}
|
|
945
962
|
function creationOpToLiveStructure(op) {
|
|
946
963
|
switch (op.type) {
|
|
947
964
|
case OpType.CreateRegister:
|
|
@@ -1151,15 +1168,12 @@ function findNonSerializableValue(value, path = "") {
|
|
|
1151
1168
|
return false;
|
|
1152
1169
|
}
|
|
1153
1170
|
function isTokenValid(token) {
|
|
1154
|
-
if (token === null) {
|
|
1155
|
-
return false;
|
|
1156
|
-
}
|
|
1157
1171
|
const tokenParts = token.split(".");
|
|
1158
1172
|
if (tokenParts.length !== 3) {
|
|
1159
1173
|
return false;
|
|
1160
1174
|
}
|
|
1161
|
-
const data =
|
|
1162
|
-
if (typeof data.exp !== "number") {
|
|
1175
|
+
const data = parseJson(atob(tokenParts[1]));
|
|
1176
|
+
if (data === void 0 || !isJsonObject(data) || typeof data.exp !== "number") {
|
|
1163
1177
|
return false;
|
|
1164
1178
|
}
|
|
1165
1179
|
const now = Date.now();
|
|
@@ -1621,19 +1635,20 @@ function makeOthers(userMap) {
|
|
|
1621
1635
|
function makeStateMachine(state, context, mockedEffects) {
|
|
1622
1636
|
const effects = mockedEffects || {
|
|
1623
1637
|
authenticate(auth, createWebSocket) {
|
|
1624
|
-
|
|
1625
|
-
|
|
1626
|
-
const
|
|
1638
|
+
const token = state.token;
|
|
1639
|
+
if (token && isTokenValid(token)) {
|
|
1640
|
+
const parsedToken = parseToken(token);
|
|
1641
|
+
const socket = createWebSocket(token);
|
|
1627
1642
|
authenticationSuccess(parsedToken, socket);
|
|
1628
1643
|
} else {
|
|
1629
|
-
return auth(context.
|
|
1644
|
+
return auth(context.roomId).then(({ token: token2 }) => {
|
|
1630
1645
|
if (state.connection.state !== "authenticating") {
|
|
1631
1646
|
return;
|
|
1632
1647
|
}
|
|
1633
|
-
const parsedToken = parseToken(
|
|
1634
|
-
const socket = createWebSocket(
|
|
1648
|
+
const parsedToken = parseToken(token2);
|
|
1649
|
+
const socket = createWebSocket(token2);
|
|
1635
1650
|
authenticationSuccess(parsedToken, socket);
|
|
1636
|
-
state.token =
|
|
1651
|
+
state.token = token2;
|
|
1637
1652
|
}).catch((er) => authenticationFailure(er));
|
|
1638
1653
|
}
|
|
1639
1654
|
},
|
|
@@ -1733,7 +1748,7 @@ function makeStateMachine(state, context, mockedEffects) {
|
|
|
1733
1748
|
generateId,
|
|
1734
1749
|
generateOpId,
|
|
1735
1750
|
dispatch: storageDispatch,
|
|
1736
|
-
roomId: context.
|
|
1751
|
+
roomId: context.roomId
|
|
1737
1752
|
});
|
|
1738
1753
|
}
|
|
1739
1754
|
function addItem(id, item) {
|
|
@@ -2061,59 +2076,72 @@ See v0.13 release notes for more information.
|
|
|
2061
2076
|
}
|
|
2062
2077
|
return { type: "enter", user: state.users[message.actor] };
|
|
2063
2078
|
}
|
|
2079
|
+
function parseServerMessage(data) {
|
|
2080
|
+
if (!isJsonObject(data)) {
|
|
2081
|
+
return null;
|
|
2082
|
+
}
|
|
2083
|
+
return data;
|
|
2084
|
+
}
|
|
2085
|
+
function parseServerMessages(text) {
|
|
2086
|
+
const data = parseJson(text);
|
|
2087
|
+
if (data === void 0) {
|
|
2088
|
+
return null;
|
|
2089
|
+
} else if (isJsonArray(data)) {
|
|
2090
|
+
return compact(data.map((item) => parseServerMessage(item)));
|
|
2091
|
+
} else {
|
|
2092
|
+
return compact([parseServerMessage(data)]);
|
|
2093
|
+
}
|
|
2094
|
+
}
|
|
2064
2095
|
function onMessage(event) {
|
|
2065
2096
|
if (event.data === "pong") {
|
|
2066
2097
|
clearTimeout(state.timeoutHandles.pongTimeout);
|
|
2067
2098
|
return;
|
|
2068
2099
|
}
|
|
2069
|
-
const
|
|
2070
|
-
|
|
2071
|
-
|
|
2072
|
-
subMessages = message;
|
|
2073
|
-
} else {
|
|
2074
|
-
subMessages.push(message);
|
|
2100
|
+
const messages = parseServerMessages(event.data);
|
|
2101
|
+
if (messages === null || messages.length === 0) {
|
|
2102
|
+
return;
|
|
2075
2103
|
}
|
|
2076
2104
|
const updates = {
|
|
2077
2105
|
storageUpdates: /* @__PURE__ */ new Map(),
|
|
2078
2106
|
others: []
|
|
2079
2107
|
};
|
|
2080
|
-
for (const
|
|
2081
|
-
switch (
|
|
2108
|
+
for (const message of messages) {
|
|
2109
|
+
switch (message.type) {
|
|
2082
2110
|
case ServerMessageType.UserJoined: {
|
|
2083
2111
|
updates.others.push(onUserJoinedMessage(message));
|
|
2084
2112
|
break;
|
|
2085
2113
|
}
|
|
2086
2114
|
case ServerMessageType.UpdatePresence: {
|
|
2087
|
-
const othersPresenceUpdate = onUpdatePresenceMessage(
|
|
2115
|
+
const othersPresenceUpdate = onUpdatePresenceMessage(message);
|
|
2088
2116
|
if (othersPresenceUpdate) {
|
|
2089
2117
|
updates.others.push(othersPresenceUpdate);
|
|
2090
2118
|
}
|
|
2091
2119
|
break;
|
|
2092
2120
|
}
|
|
2093
2121
|
case ServerMessageType.Event: {
|
|
2094
|
-
onEvent(
|
|
2122
|
+
onEvent(message);
|
|
2095
2123
|
break;
|
|
2096
2124
|
}
|
|
2097
2125
|
case ServerMessageType.UserLeft: {
|
|
2098
|
-
const event2 = onUserLeftMessage(
|
|
2126
|
+
const event2 = onUserLeftMessage(message);
|
|
2099
2127
|
if (event2) {
|
|
2100
2128
|
updates.others.push(event2);
|
|
2101
2129
|
}
|
|
2102
2130
|
break;
|
|
2103
2131
|
}
|
|
2104
2132
|
case ServerMessageType.RoomState: {
|
|
2105
|
-
updates.others.push(onRoomStateMessage(
|
|
2133
|
+
updates.others.push(onRoomStateMessage(message));
|
|
2106
2134
|
break;
|
|
2107
2135
|
}
|
|
2108
2136
|
case ServerMessageType.InitialStorageState: {
|
|
2109
2137
|
const offlineOps = new Map(state.offlineOperations);
|
|
2110
|
-
createOrUpdateRootFromMessage(
|
|
2138
|
+
createOrUpdateRootFromMessage(message);
|
|
2111
2139
|
applyAndSendOfflineOps(offlineOps);
|
|
2112
2140
|
_getInitialStateResolver == null ? void 0 : _getInitialStateResolver();
|
|
2113
2141
|
break;
|
|
2114
2142
|
}
|
|
2115
2143
|
case ServerMessageType.UpdateStorage: {
|
|
2116
|
-
const applyResult = apply(
|
|
2144
|
+
const applyResult = apply(message.ops, false);
|
|
2117
2145
|
applyResult.updates.storageUpdates.forEach((value, key) => {
|
|
2118
2146
|
updates.storageUpdates.set(key, mergeStorageUpdates(updates.storageUpdates.get(key), value));
|
|
2119
2147
|
});
|
|
@@ -2531,7 +2559,7 @@ function createRoom(options, context) {
|
|
|
2531
2559
|
const state = defaultState(options.defaultPresence, options.defaultStorageRoot);
|
|
2532
2560
|
const machine = makeStateMachine(state, context);
|
|
2533
2561
|
const room = {
|
|
2534
|
-
id: context.
|
|
2562
|
+
id: context.roomId,
|
|
2535
2563
|
getConnectionState: machine.selectors.getConnectionState,
|
|
2536
2564
|
getSelf: machine.selectors.getSelf,
|
|
2537
2565
|
subscribe: machine.subscribe,
|
|
@@ -2572,11 +2600,15 @@ function parseToken(token) {
|
|
|
2572
2600
|
if (tokenParts.length !== 3) {
|
|
2573
2601
|
throw new Error(`Authentication error. Liveblocks could not parse the response of your authentication endpoint`);
|
|
2574
2602
|
}
|
|
2575
|
-
const data =
|
|
2576
|
-
if (typeof data.actor
|
|
2577
|
-
|
|
2603
|
+
const data = parseJson(atob(tokenParts[1]));
|
|
2604
|
+
if (data !== void 0 && isJsonObject(data) && typeof data.actor === "number" && (data.id === void 0 || typeof data.id === "string")) {
|
|
2605
|
+
return {
|
|
2606
|
+
actor: data.actor,
|
|
2607
|
+
id: data.id,
|
|
2608
|
+
info: data.info
|
|
2609
|
+
};
|
|
2578
2610
|
}
|
|
2579
|
-
|
|
2611
|
+
throw new Error(`Authentication error. Liveblocks could not parse the response of your authentication endpoint`);
|
|
2580
2612
|
}
|
|
2581
2613
|
function prepareCreateWebSocket(liveblocksServer, WebSocketPolyfill) {
|
|
2582
2614
|
if (typeof window === "undefined" && WebSocketPolyfill == null) {
|
|
@@ -2654,7 +2686,7 @@ function createClient(options) {
|
|
|
2654
2686
|
defaultPresence: options2.defaultPresence,
|
|
2655
2687
|
defaultStorageRoot: options2.defaultStorageRoot
|
|
2656
2688
|
}, {
|
|
2657
|
-
|
|
2689
|
+
roomId,
|
|
2658
2690
|
throttleDelay,
|
|
2659
2691
|
WebSocketPolyfill: clientOptions.WebSocketPolyfill,
|
|
2660
2692
|
fetchPolyfill: clientOptions.fetchPolyfill,
|
package/lib/esm/index.mjs
CHANGED
|
@@ -915,6 +915,20 @@ class LiveMap extends AbstractCrdt {
|
|
|
915
915
|
}
|
|
916
916
|
}
|
|
917
917
|
|
|
918
|
+
function parseJson(rawMessage) {
|
|
919
|
+
try {
|
|
920
|
+
return JSON.parse(rawMessage);
|
|
921
|
+
} catch (e) {
|
|
922
|
+
return void 0;
|
|
923
|
+
}
|
|
924
|
+
}
|
|
925
|
+
function isJsonArray(data) {
|
|
926
|
+
return Array.isArray(data);
|
|
927
|
+
}
|
|
928
|
+
function isJsonObject(data) {
|
|
929
|
+
return data !== null && typeof data === "object" && !isJsonArray(data);
|
|
930
|
+
}
|
|
931
|
+
|
|
918
932
|
var __defProp$2 = Object.defineProperty;
|
|
919
933
|
var __defProps$2 = Object.defineProperties;
|
|
920
934
|
var __getOwnPropDescs$2 = Object.getOwnPropertyDescriptors;
|
|
@@ -942,6 +956,9 @@ function remove(array, item) {
|
|
|
942
956
|
}
|
|
943
957
|
}
|
|
944
958
|
}
|
|
959
|
+
function compact(items) {
|
|
960
|
+
return items.filter((item) => item != null);
|
|
961
|
+
}
|
|
945
962
|
function creationOpToLiveStructure(op) {
|
|
946
963
|
switch (op.type) {
|
|
947
964
|
case OpType.CreateRegister:
|
|
@@ -1151,15 +1168,12 @@ function findNonSerializableValue(value, path = "") {
|
|
|
1151
1168
|
return false;
|
|
1152
1169
|
}
|
|
1153
1170
|
function isTokenValid(token) {
|
|
1154
|
-
if (token === null) {
|
|
1155
|
-
return false;
|
|
1156
|
-
}
|
|
1157
1171
|
const tokenParts = token.split(".");
|
|
1158
1172
|
if (tokenParts.length !== 3) {
|
|
1159
1173
|
return false;
|
|
1160
1174
|
}
|
|
1161
|
-
const data =
|
|
1162
|
-
if (typeof data.exp !== "number") {
|
|
1175
|
+
const data = parseJson(atob(tokenParts[1]));
|
|
1176
|
+
if (data === void 0 || !isJsonObject(data) || typeof data.exp !== "number") {
|
|
1163
1177
|
return false;
|
|
1164
1178
|
}
|
|
1165
1179
|
const now = Date.now();
|
|
@@ -1621,19 +1635,20 @@ function makeOthers(userMap) {
|
|
|
1621
1635
|
function makeStateMachine(state, context, mockedEffects) {
|
|
1622
1636
|
const effects = mockedEffects || {
|
|
1623
1637
|
authenticate(auth, createWebSocket) {
|
|
1624
|
-
|
|
1625
|
-
|
|
1626
|
-
const
|
|
1638
|
+
const token = state.token;
|
|
1639
|
+
if (token && isTokenValid(token)) {
|
|
1640
|
+
const parsedToken = parseToken(token);
|
|
1641
|
+
const socket = createWebSocket(token);
|
|
1627
1642
|
authenticationSuccess(parsedToken, socket);
|
|
1628
1643
|
} else {
|
|
1629
|
-
return auth(context.
|
|
1644
|
+
return auth(context.roomId).then(({ token: token2 }) => {
|
|
1630
1645
|
if (state.connection.state !== "authenticating") {
|
|
1631
1646
|
return;
|
|
1632
1647
|
}
|
|
1633
|
-
const parsedToken = parseToken(
|
|
1634
|
-
const socket = createWebSocket(
|
|
1648
|
+
const parsedToken = parseToken(token2);
|
|
1649
|
+
const socket = createWebSocket(token2);
|
|
1635
1650
|
authenticationSuccess(parsedToken, socket);
|
|
1636
|
-
state.token =
|
|
1651
|
+
state.token = token2;
|
|
1637
1652
|
}).catch((er) => authenticationFailure(er));
|
|
1638
1653
|
}
|
|
1639
1654
|
},
|
|
@@ -1733,7 +1748,7 @@ function makeStateMachine(state, context, mockedEffects) {
|
|
|
1733
1748
|
generateId,
|
|
1734
1749
|
generateOpId,
|
|
1735
1750
|
dispatch: storageDispatch,
|
|
1736
|
-
roomId: context.
|
|
1751
|
+
roomId: context.roomId
|
|
1737
1752
|
});
|
|
1738
1753
|
}
|
|
1739
1754
|
function addItem(id, item) {
|
|
@@ -2061,59 +2076,72 @@ See v0.13 release notes for more information.
|
|
|
2061
2076
|
}
|
|
2062
2077
|
return { type: "enter", user: state.users[message.actor] };
|
|
2063
2078
|
}
|
|
2079
|
+
function parseServerMessage(data) {
|
|
2080
|
+
if (!isJsonObject(data)) {
|
|
2081
|
+
return null;
|
|
2082
|
+
}
|
|
2083
|
+
return data;
|
|
2084
|
+
}
|
|
2085
|
+
function parseServerMessages(text) {
|
|
2086
|
+
const data = parseJson(text);
|
|
2087
|
+
if (data === void 0) {
|
|
2088
|
+
return null;
|
|
2089
|
+
} else if (isJsonArray(data)) {
|
|
2090
|
+
return compact(data.map((item) => parseServerMessage(item)));
|
|
2091
|
+
} else {
|
|
2092
|
+
return compact([parseServerMessage(data)]);
|
|
2093
|
+
}
|
|
2094
|
+
}
|
|
2064
2095
|
function onMessage(event) {
|
|
2065
2096
|
if (event.data === "pong") {
|
|
2066
2097
|
clearTimeout(state.timeoutHandles.pongTimeout);
|
|
2067
2098
|
return;
|
|
2068
2099
|
}
|
|
2069
|
-
const
|
|
2070
|
-
|
|
2071
|
-
|
|
2072
|
-
subMessages = message;
|
|
2073
|
-
} else {
|
|
2074
|
-
subMessages.push(message);
|
|
2100
|
+
const messages = parseServerMessages(event.data);
|
|
2101
|
+
if (messages === null || messages.length === 0) {
|
|
2102
|
+
return;
|
|
2075
2103
|
}
|
|
2076
2104
|
const updates = {
|
|
2077
2105
|
storageUpdates: /* @__PURE__ */ new Map(),
|
|
2078
2106
|
others: []
|
|
2079
2107
|
};
|
|
2080
|
-
for (const
|
|
2081
|
-
switch (
|
|
2108
|
+
for (const message of messages) {
|
|
2109
|
+
switch (message.type) {
|
|
2082
2110
|
case ServerMessageType.UserJoined: {
|
|
2083
2111
|
updates.others.push(onUserJoinedMessage(message));
|
|
2084
2112
|
break;
|
|
2085
2113
|
}
|
|
2086
2114
|
case ServerMessageType.UpdatePresence: {
|
|
2087
|
-
const othersPresenceUpdate = onUpdatePresenceMessage(
|
|
2115
|
+
const othersPresenceUpdate = onUpdatePresenceMessage(message);
|
|
2088
2116
|
if (othersPresenceUpdate) {
|
|
2089
2117
|
updates.others.push(othersPresenceUpdate);
|
|
2090
2118
|
}
|
|
2091
2119
|
break;
|
|
2092
2120
|
}
|
|
2093
2121
|
case ServerMessageType.Event: {
|
|
2094
|
-
onEvent(
|
|
2122
|
+
onEvent(message);
|
|
2095
2123
|
break;
|
|
2096
2124
|
}
|
|
2097
2125
|
case ServerMessageType.UserLeft: {
|
|
2098
|
-
const event2 = onUserLeftMessage(
|
|
2126
|
+
const event2 = onUserLeftMessage(message);
|
|
2099
2127
|
if (event2) {
|
|
2100
2128
|
updates.others.push(event2);
|
|
2101
2129
|
}
|
|
2102
2130
|
break;
|
|
2103
2131
|
}
|
|
2104
2132
|
case ServerMessageType.RoomState: {
|
|
2105
|
-
updates.others.push(onRoomStateMessage(
|
|
2133
|
+
updates.others.push(onRoomStateMessage(message));
|
|
2106
2134
|
break;
|
|
2107
2135
|
}
|
|
2108
2136
|
case ServerMessageType.InitialStorageState: {
|
|
2109
2137
|
const offlineOps = new Map(state.offlineOperations);
|
|
2110
|
-
createOrUpdateRootFromMessage(
|
|
2138
|
+
createOrUpdateRootFromMessage(message);
|
|
2111
2139
|
applyAndSendOfflineOps(offlineOps);
|
|
2112
2140
|
_getInitialStateResolver == null ? void 0 : _getInitialStateResolver();
|
|
2113
2141
|
break;
|
|
2114
2142
|
}
|
|
2115
2143
|
case ServerMessageType.UpdateStorage: {
|
|
2116
|
-
const applyResult = apply(
|
|
2144
|
+
const applyResult = apply(message.ops, false);
|
|
2117
2145
|
applyResult.updates.storageUpdates.forEach((value, key) => {
|
|
2118
2146
|
updates.storageUpdates.set(key, mergeStorageUpdates(updates.storageUpdates.get(key), value));
|
|
2119
2147
|
});
|
|
@@ -2531,7 +2559,7 @@ function createRoom(options, context) {
|
|
|
2531
2559
|
const state = defaultState(options.defaultPresence, options.defaultStorageRoot);
|
|
2532
2560
|
const machine = makeStateMachine(state, context);
|
|
2533
2561
|
const room = {
|
|
2534
|
-
id: context.
|
|
2562
|
+
id: context.roomId,
|
|
2535
2563
|
getConnectionState: machine.selectors.getConnectionState,
|
|
2536
2564
|
getSelf: machine.selectors.getSelf,
|
|
2537
2565
|
subscribe: machine.subscribe,
|
|
@@ -2572,11 +2600,15 @@ function parseToken(token) {
|
|
|
2572
2600
|
if (tokenParts.length !== 3) {
|
|
2573
2601
|
throw new Error(`Authentication error. Liveblocks could not parse the response of your authentication endpoint`);
|
|
2574
2602
|
}
|
|
2575
|
-
const data =
|
|
2576
|
-
if (typeof data.actor
|
|
2577
|
-
|
|
2603
|
+
const data = parseJson(atob(tokenParts[1]));
|
|
2604
|
+
if (data !== void 0 && isJsonObject(data) && typeof data.actor === "number" && (data.id === void 0 || typeof data.id === "string")) {
|
|
2605
|
+
return {
|
|
2606
|
+
actor: data.actor,
|
|
2607
|
+
id: data.id,
|
|
2608
|
+
info: data.info
|
|
2609
|
+
};
|
|
2578
2610
|
}
|
|
2579
|
-
|
|
2611
|
+
throw new Error(`Authentication error. Liveblocks could not parse the response of your authentication endpoint`);
|
|
2580
2612
|
}
|
|
2581
2613
|
function prepareCreateWebSocket(liveblocksServer, WebSocketPolyfill) {
|
|
2582
2614
|
if (typeof window === "undefined" && WebSocketPolyfill == null) {
|
|
@@ -2654,7 +2686,7 @@ function createClient(options) {
|
|
|
2654
2686
|
defaultPresence: options2.defaultPresence,
|
|
2655
2687
|
defaultStorageRoot: options2.defaultStorageRoot
|
|
2656
2688
|
}, {
|
|
2657
|
-
|
|
2689
|
+
roomId,
|
|
2658
2690
|
throttleDelay,
|
|
2659
2691
|
WebSocketPolyfill: clientOptions.WebSocketPolyfill,
|
|
2660
2692
|
fetchPolyfill: clientOptions.fetchPolyfill,
|
package/lib/index.d.ts
CHANGED
|
@@ -201,6 +201,10 @@ declare type UpdateDelta = {
|
|
|
201
201
|
} | {
|
|
202
202
|
type: "delete";
|
|
203
203
|
};
|
|
204
|
+
/**
|
|
205
|
+
* A LiveMap notification that is sent in-client to any subscribers whenever
|
|
206
|
+
* one or more of the values inside the LiveMap instance have changed.
|
|
207
|
+
*/
|
|
204
208
|
declare type LiveMapUpdates<TKey extends string, TValue extends Lson> = {
|
|
205
209
|
type: "LiveMap";
|
|
206
210
|
node: LiveMap<TKey, TValue>;
|
|
@@ -213,6 +217,10 @@ declare type LiveObjectUpdateDelta<O extends {
|
|
|
213
217
|
}> = {
|
|
214
218
|
[K in keyof O]?: UpdateDelta | undefined;
|
|
215
219
|
};
|
|
220
|
+
/**
|
|
221
|
+
* A LiveObject notification that is sent in-client to any subscribers whenever
|
|
222
|
+
* one or more of the entries inside the LiveObject instance have changed.
|
|
223
|
+
*/
|
|
216
224
|
declare type LiveObjectUpdates<TData extends LsonObject> = {
|
|
217
225
|
type: "LiveObject";
|
|
218
226
|
node: LiveObject<TData>;
|
|
@@ -235,6 +243,10 @@ declare type LiveListUpdateDelta = {
|
|
|
235
243
|
item: any;
|
|
236
244
|
type: "set";
|
|
237
245
|
};
|
|
246
|
+
/**
|
|
247
|
+
* A LiveList notification that is sent in-client to any subscribers whenever
|
|
248
|
+
* one or more of the items inside the LiveList instance have changed.
|
|
249
|
+
*/
|
|
238
250
|
declare type LiveListUpdates<TItem extends Lson> = {
|
|
239
251
|
type: "LiveList";
|
|
240
252
|
node: LiveList<TItem>;
|
|
@@ -248,6 +260,11 @@ declare type BroadcastOptions = {
|
|
|
248
260
|
*/
|
|
249
261
|
shouldQueueEventIfNotReady: boolean;
|
|
250
262
|
};
|
|
263
|
+
/**
|
|
264
|
+
* The payload of notifications sent (in-client) when LiveStructures change.
|
|
265
|
+
* Messages of this kind are not originating from the network, but are 100%
|
|
266
|
+
* in-client.
|
|
267
|
+
*/
|
|
251
268
|
declare type StorageUpdate = LiveMapUpdates<string, Lson> | LiveObjectUpdates<LsonObject> | LiveListUpdates<Lson>;
|
|
252
269
|
declare type Client = {
|
|
253
270
|
/**
|
package/lib/index.js
CHANGED
|
@@ -1535,6 +1535,20 @@ var LiveMap = function (_AbstractCrdt) {
|
|
|
1535
1535
|
return LiveMap;
|
|
1536
1536
|
}(AbstractCrdt);
|
|
1537
1537
|
|
|
1538
|
+
function parseJson(rawMessage) {
|
|
1539
|
+
try {
|
|
1540
|
+
return JSON.parse(rawMessage);
|
|
1541
|
+
} catch (e) {
|
|
1542
|
+
return undefined;
|
|
1543
|
+
}
|
|
1544
|
+
}
|
|
1545
|
+
function isJsonArray(data) {
|
|
1546
|
+
return Array.isArray(data);
|
|
1547
|
+
}
|
|
1548
|
+
function isJsonObject(data) {
|
|
1549
|
+
return data !== null && typeof data === "object" && !isJsonArray(data);
|
|
1550
|
+
}
|
|
1551
|
+
|
|
1538
1552
|
function remove(array, item) {
|
|
1539
1553
|
for (var i = 0; i < array.length; i++) {
|
|
1540
1554
|
if (array[i] === item) {
|
|
@@ -1543,6 +1557,11 @@ function remove(array, item) {
|
|
|
1543
1557
|
}
|
|
1544
1558
|
}
|
|
1545
1559
|
}
|
|
1560
|
+
function compact(items) {
|
|
1561
|
+
return items.filter(function (item) {
|
|
1562
|
+
return item != null;
|
|
1563
|
+
});
|
|
1564
|
+
}
|
|
1546
1565
|
function creationOpToLiveStructure(op) {
|
|
1547
1566
|
switch (op.type) {
|
|
1548
1567
|
case OpType.CreateRegister:
|
|
@@ -1804,19 +1823,15 @@ function findNonSerializableValue(value, path) {
|
|
|
1804
1823
|
return false;
|
|
1805
1824
|
}
|
|
1806
1825
|
function isTokenValid(token) {
|
|
1807
|
-
if (token === null) {
|
|
1808
|
-
return false;
|
|
1809
|
-
}
|
|
1810
|
-
|
|
1811
1826
|
var tokenParts = token.split(".");
|
|
1812
1827
|
|
|
1813
1828
|
if (tokenParts.length !== 3) {
|
|
1814
1829
|
return false;
|
|
1815
1830
|
}
|
|
1816
1831
|
|
|
1817
|
-
var data =
|
|
1832
|
+
var data = parseJson(atob(tokenParts[1]));
|
|
1818
1833
|
|
|
1819
|
-
if (typeof data.exp !== "number") {
|
|
1834
|
+
if (data === undefined || !isJsonObject(data) || typeof data.exp !== "number") {
|
|
1820
1835
|
return false;
|
|
1821
1836
|
}
|
|
1822
1837
|
|
|
@@ -2461,12 +2476,14 @@ function makeOthers(userMap) {
|
|
|
2461
2476
|
function makeStateMachine(state, context, mockedEffects) {
|
|
2462
2477
|
var effects = mockedEffects || {
|
|
2463
2478
|
authenticate: function authenticate(auth, createWebSocket) {
|
|
2464
|
-
|
|
2465
|
-
|
|
2466
|
-
|
|
2479
|
+
var token = state.token;
|
|
2480
|
+
|
|
2481
|
+
if (token && isTokenValid(token)) {
|
|
2482
|
+
var parsedToken = parseToken(token);
|
|
2483
|
+
var socket = createWebSocket(token);
|
|
2467
2484
|
authenticationSuccess(parsedToken, socket);
|
|
2468
2485
|
} else {
|
|
2469
|
-
return auth(context.
|
|
2486
|
+
return auth(context.roomId).then(function (_ref2) {
|
|
2470
2487
|
var token = _ref2.token;
|
|
2471
2488
|
|
|
2472
2489
|
if (state.connection.state !== "authenticating") {
|
|
@@ -2604,7 +2621,7 @@ function makeStateMachine(state, context, mockedEffects) {
|
|
|
2604
2621
|
generateId: generateId,
|
|
2605
2622
|
generateOpId: generateOpId,
|
|
2606
2623
|
dispatch: storageDispatch,
|
|
2607
|
-
roomId: context.
|
|
2624
|
+
roomId: context.roomId
|
|
2608
2625
|
});
|
|
2609
2626
|
}
|
|
2610
2627
|
|
|
@@ -3066,19 +3083,38 @@ function makeStateMachine(state, context, mockedEffects) {
|
|
|
3066
3083
|
};
|
|
3067
3084
|
}
|
|
3068
3085
|
|
|
3086
|
+
function parseServerMessage(data) {
|
|
3087
|
+
if (!isJsonObject(data)) {
|
|
3088
|
+
return null;
|
|
3089
|
+
}
|
|
3090
|
+
|
|
3091
|
+
return data;
|
|
3092
|
+
}
|
|
3093
|
+
|
|
3094
|
+
function parseServerMessages(text) {
|
|
3095
|
+
var data = parseJson(text);
|
|
3096
|
+
|
|
3097
|
+
if (data === undefined) {
|
|
3098
|
+
return null;
|
|
3099
|
+
} else if (isJsonArray(data)) {
|
|
3100
|
+
return compact(data.map(function (item) {
|
|
3101
|
+
return parseServerMessage(item);
|
|
3102
|
+
}));
|
|
3103
|
+
} else {
|
|
3104
|
+
return compact([parseServerMessage(data)]);
|
|
3105
|
+
}
|
|
3106
|
+
}
|
|
3107
|
+
|
|
3069
3108
|
function onMessage(event) {
|
|
3070
3109
|
if (event.data === "pong") {
|
|
3071
3110
|
clearTimeout(state.timeoutHandles.pongTimeout);
|
|
3072
3111
|
return;
|
|
3073
3112
|
}
|
|
3074
3113
|
|
|
3075
|
-
var
|
|
3076
|
-
var subMessages = [];
|
|
3114
|
+
var messages = parseServerMessages(event.data);
|
|
3077
3115
|
|
|
3078
|
-
if (
|
|
3079
|
-
|
|
3080
|
-
} else {
|
|
3081
|
-
subMessages.push(message);
|
|
3116
|
+
if (messages === null || messages.length === 0) {
|
|
3117
|
+
return;
|
|
3082
3118
|
}
|
|
3083
3119
|
|
|
3084
3120
|
var updates = {
|
|
@@ -3086,10 +3122,10 @@ function makeStateMachine(state, context, mockedEffects) {
|
|
|
3086
3122
|
others: []
|
|
3087
3123
|
};
|
|
3088
3124
|
|
|
3089
|
-
for (var _iterator9 = _createForOfIteratorHelperLoose(
|
|
3090
|
-
var
|
|
3125
|
+
for (var _iterator9 = _createForOfIteratorHelperLoose(messages), _step9; !(_step9 = _iterator9()).done;) {
|
|
3126
|
+
var message = _step9.value;
|
|
3091
3127
|
|
|
3092
|
-
switch (
|
|
3128
|
+
switch (message.type) {
|
|
3093
3129
|
case ServerMessageType.UserJoined:
|
|
3094
3130
|
{
|
|
3095
3131
|
updates.others.push(onUserJoinedMessage(message));
|
|
@@ -3098,7 +3134,7 @@ function makeStateMachine(state, context, mockedEffects) {
|
|
|
3098
3134
|
|
|
3099
3135
|
case ServerMessageType.UpdatePresence:
|
|
3100
3136
|
{
|
|
3101
|
-
var othersPresenceUpdate = onUpdatePresenceMessage(
|
|
3137
|
+
var othersPresenceUpdate = onUpdatePresenceMessage(message);
|
|
3102
3138
|
|
|
3103
3139
|
if (othersPresenceUpdate) {
|
|
3104
3140
|
updates.others.push(othersPresenceUpdate);
|
|
@@ -3109,13 +3145,13 @@ function makeStateMachine(state, context, mockedEffects) {
|
|
|
3109
3145
|
|
|
3110
3146
|
case ServerMessageType.Event:
|
|
3111
3147
|
{
|
|
3112
|
-
onEvent(
|
|
3148
|
+
onEvent(message);
|
|
3113
3149
|
break;
|
|
3114
3150
|
}
|
|
3115
3151
|
|
|
3116
3152
|
case ServerMessageType.UserLeft:
|
|
3117
3153
|
{
|
|
3118
|
-
var _event = onUserLeftMessage(
|
|
3154
|
+
var _event = onUserLeftMessage(message);
|
|
3119
3155
|
|
|
3120
3156
|
if (_event) {
|
|
3121
3157
|
updates.others.push(_event);
|
|
@@ -3126,14 +3162,14 @@ function makeStateMachine(state, context, mockedEffects) {
|
|
|
3126
3162
|
|
|
3127
3163
|
case ServerMessageType.RoomState:
|
|
3128
3164
|
{
|
|
3129
|
-
updates.others.push(onRoomStateMessage(
|
|
3165
|
+
updates.others.push(onRoomStateMessage(message));
|
|
3130
3166
|
break;
|
|
3131
3167
|
}
|
|
3132
3168
|
|
|
3133
3169
|
case ServerMessageType.InitialStorageState:
|
|
3134
3170
|
{
|
|
3135
3171
|
var offlineOps = new Map(state.offlineOperations);
|
|
3136
|
-
createOrUpdateRootFromMessage(
|
|
3172
|
+
createOrUpdateRootFromMessage(message);
|
|
3137
3173
|
applyAndSendOfflineOps(offlineOps);
|
|
3138
3174
|
_getInitialStateResolver == null ? void 0 : _getInitialStateResolver();
|
|
3139
3175
|
break;
|
|
@@ -3141,7 +3177,7 @@ function makeStateMachine(state, context, mockedEffects) {
|
|
|
3141
3177
|
|
|
3142
3178
|
case ServerMessageType.UpdateStorage:
|
|
3143
3179
|
{
|
|
3144
|
-
var applyResult = apply(
|
|
3180
|
+
var applyResult = apply(message.ops, false);
|
|
3145
3181
|
applyResult.updates.storageUpdates.forEach(function (value, key) {
|
|
3146
3182
|
updates.storageUpdates.set(key, mergeStorageUpdates(updates.storageUpdates.get(key), value));
|
|
3147
3183
|
});
|
|
@@ -3701,7 +3737,7 @@ function createRoom(options, context) {
|
|
|
3701
3737
|
var state = defaultState(options.defaultPresence, options.defaultStorageRoot);
|
|
3702
3738
|
var machine = makeStateMachine(state, context);
|
|
3703
3739
|
var room = {
|
|
3704
|
-
id: context.
|
|
3740
|
+
id: context.roomId,
|
|
3705
3741
|
getConnectionState: machine.selectors.getConnectionState,
|
|
3706
3742
|
getSelf: machine.selectors.getSelf,
|
|
3707
3743
|
subscribe: machine.subscribe,
|
|
@@ -3753,13 +3789,17 @@ function parseToken(token) {
|
|
|
3753
3789
|
throw new Error("Authentication error. Liveblocks could not parse the response of your authentication endpoint");
|
|
3754
3790
|
}
|
|
3755
3791
|
|
|
3756
|
-
var data =
|
|
3792
|
+
var data = parseJson(atob(tokenParts[1]));
|
|
3757
3793
|
|
|
3758
|
-
if (typeof data.actor
|
|
3759
|
-
|
|
3794
|
+
if (data !== undefined && isJsonObject(data) && typeof data.actor === "number" && (data.id === undefined || typeof data.id === "string")) {
|
|
3795
|
+
return {
|
|
3796
|
+
actor: data.actor,
|
|
3797
|
+
id: data.id,
|
|
3798
|
+
info: data.info
|
|
3799
|
+
};
|
|
3760
3800
|
}
|
|
3761
3801
|
|
|
3762
|
-
|
|
3802
|
+
throw new Error("Authentication error. Liveblocks could not parse the response of your authentication endpoint");
|
|
3763
3803
|
}
|
|
3764
3804
|
|
|
3765
3805
|
function prepareCreateWebSocket(liveblocksServer, WebSocketPolyfill) {
|
|
@@ -3865,7 +3905,7 @@ function createClient(options) {
|
|
|
3865
3905
|
defaultPresence: options.defaultPresence,
|
|
3866
3906
|
defaultStorageRoot: options.defaultStorageRoot
|
|
3867
3907
|
}, {
|
|
3868
|
-
|
|
3908
|
+
roomId: roomId,
|
|
3869
3909
|
throttleDelay: throttleDelay,
|
|
3870
3910
|
WebSocketPolyfill: clientOptions.WebSocketPolyfill,
|
|
3871
3911
|
fetchPolyfill: clientOptions.fetchPolyfill,
|
package/lib/internal.d.ts
CHANGED
|
@@ -17,6 +17,9 @@ declare type JsonObject = {
|
|
|
17
17
|
|
|
18
18
|
declare type Presence = Record<string, unknown>;
|
|
19
19
|
|
|
20
|
+
/**
|
|
21
|
+
* Messages that can be sent from the server to the client.
|
|
22
|
+
*/
|
|
20
23
|
declare type ServerMessage = UpdatePresenceMessage | UserJoinMessage | UserLeftMessage | EventMessage | RoomStateMessage | InitialDocumentStateMessage | UpdateStorageMessage;
|
|
21
24
|
declare enum ServerMessageType {
|
|
22
25
|
UpdatePresence = 100,
|
|
@@ -27,45 +30,116 @@ declare enum ServerMessageType {
|
|
|
27
30
|
InitialStorageState = 200,
|
|
28
31
|
UpdateStorage = 201
|
|
29
32
|
}
|
|
33
|
+
/**
|
|
34
|
+
* Sent by the WebSocket server to a single client in response to the client
|
|
35
|
+
* joining the Room, to provide the initial state of the Room. The payload
|
|
36
|
+
* includes a list of all other Users that already are in the Room.
|
|
37
|
+
*/
|
|
30
38
|
declare type RoomStateMessage = {
|
|
31
39
|
type: ServerMessageType.RoomState;
|
|
32
40
|
users: {
|
|
33
41
|
[actor: number]: {
|
|
34
42
|
id?: string;
|
|
35
|
-
info?:
|
|
43
|
+
info?: Json;
|
|
36
44
|
};
|
|
37
45
|
};
|
|
38
46
|
};
|
|
47
|
+
/**
|
|
48
|
+
* Sent by the WebSocket server and broadcasted to all clients to announce that
|
|
49
|
+
* a User updated their presence. For example, when a user moves their cursor.
|
|
50
|
+
*
|
|
51
|
+
* In most cases, the data payload will only include the fields from the
|
|
52
|
+
* Presence that have been changed since the last announcement. However, after
|
|
53
|
+
* a new user joins a room, a "full presence" will be announced so the newly
|
|
54
|
+
* connected user will get each other's user full presence at least once. In
|
|
55
|
+
* those cases, the `targetActor` field indicates the newly connected client,
|
|
56
|
+
* so all other existing clients can ignore this broadcasted message.
|
|
57
|
+
*/
|
|
39
58
|
declare type UpdatePresenceMessage = {
|
|
40
59
|
type: ServerMessageType.UpdatePresence;
|
|
60
|
+
/**
|
|
61
|
+
* The User whose Presence has changed.
|
|
62
|
+
*/
|
|
41
63
|
actor: number;
|
|
64
|
+
/**
|
|
65
|
+
* The partial or full Presence of a User. If the `targetActor` field is set,
|
|
66
|
+
* this will be the full Presence, otherwise it only contain the fields that
|
|
67
|
+
* have changed since the last broadcast.
|
|
68
|
+
*/
|
|
42
69
|
data: Presence;
|
|
70
|
+
/**
|
|
71
|
+
* If this message was sent in response to a newly joined user, this field
|
|
72
|
+
* indicates which client this message is for. Other existing clients may
|
|
73
|
+
* ignore this message if this message isn't targeted for them.
|
|
74
|
+
*/
|
|
43
75
|
targetActor?: number;
|
|
44
76
|
};
|
|
77
|
+
/**
|
|
78
|
+
* Sent by the WebSocket server and broadcasted to all clients to announce that
|
|
79
|
+
* a new User has joined the Room.
|
|
80
|
+
*/
|
|
45
81
|
declare type UserJoinMessage = {
|
|
46
82
|
type: ServerMessageType.UserJoined;
|
|
47
83
|
actor: number;
|
|
84
|
+
/**
|
|
85
|
+
* The id of the User that has been set in the authentication endpoint.
|
|
86
|
+
* Useful to get additional information about the connected user.
|
|
87
|
+
*/
|
|
48
88
|
id?: string;
|
|
49
|
-
|
|
89
|
+
/**
|
|
90
|
+
* Additional user information that has been set in the authentication
|
|
91
|
+
* endpoint.
|
|
92
|
+
*/
|
|
93
|
+
info?: Json;
|
|
50
94
|
};
|
|
95
|
+
/**
|
|
96
|
+
* Sent by the WebSocket server and broadcasted to all clients to announce that
|
|
97
|
+
* a new User has left the Room.
|
|
98
|
+
*/
|
|
51
99
|
declare type UserLeftMessage = {
|
|
52
100
|
type: ServerMessageType.UserLeft;
|
|
53
101
|
actor: number;
|
|
54
102
|
};
|
|
103
|
+
/**
|
|
104
|
+
* Sent by the WebSocket server and broadcasted to all clients to announce that
|
|
105
|
+
* a User broadcasted an Event to everyone in the Room.
|
|
106
|
+
*/
|
|
55
107
|
declare type EventMessage = {
|
|
56
108
|
type: ServerMessageType.Event;
|
|
109
|
+
/**
|
|
110
|
+
* The User who broadcasted the Event.
|
|
111
|
+
*/
|
|
57
112
|
actor: number;
|
|
113
|
+
/**
|
|
114
|
+
* The arbitrary payload of the Event. This can be any JSON value. Clients
|
|
115
|
+
* will have to manually verify/decode this event.
|
|
116
|
+
*/
|
|
58
117
|
event: Json;
|
|
59
118
|
};
|
|
60
119
|
declare type SerializedCrdtWithId = [id: string, crdt: SerializedCrdt];
|
|
120
|
+
/**
|
|
121
|
+
* Sent by the WebSocket server to a single client in response to the client
|
|
122
|
+
* joining the Room, to provide the initial Storage state of the Room. The
|
|
123
|
+
* payload includes the entire Storage document.
|
|
124
|
+
*/
|
|
61
125
|
declare type InitialDocumentStateMessage = {
|
|
62
126
|
type: ServerMessageType.InitialStorageState;
|
|
63
127
|
items: SerializedCrdtWithId[];
|
|
64
128
|
};
|
|
129
|
+
/**
|
|
130
|
+
* Sent by the WebSocket server and broadcasted to all clients to announce that
|
|
131
|
+
* a change occurred in the Storage document.
|
|
132
|
+
*
|
|
133
|
+
* The payload of this message contains a list of Ops (aka incremental
|
|
134
|
+
* mutations to make to the initially loaded document).
|
|
135
|
+
*/
|
|
65
136
|
declare type UpdateStorageMessage = {
|
|
66
137
|
type: ServerMessageType.UpdateStorage;
|
|
67
138
|
ops: Op[];
|
|
68
139
|
};
|
|
140
|
+
/**
|
|
141
|
+
* Messages that can be sent from the client to the server.
|
|
142
|
+
*/
|
|
69
143
|
declare type ClientMessage = ClientEventMessage | UpdatePresenceClientMessage | UpdateStorageClientMessage | FetchStorageClientMessage;
|
|
70
144
|
declare enum ClientMessageType {
|
|
71
145
|
UpdatePresence = 100,
|
|
@@ -129,6 +203,10 @@ declare enum OpType {
|
|
|
129
203
|
CreateMap = 7,
|
|
130
204
|
CreateRegister = 8
|
|
131
205
|
}
|
|
206
|
+
/**
|
|
207
|
+
* These operations are the payload for {@link UpdateStorageMessage} messages
|
|
208
|
+
* only.
|
|
209
|
+
*/
|
|
132
210
|
declare type Op = CreateObjectOp | UpdateObjectOp | DeleteCrdtOp | CreateListOp | SetParentKeyOp | DeleteObjectKeyOp | CreateMapOp | CreateRegisterOp;
|
|
133
211
|
declare type CreateOp = CreateObjectOp | CreateRegisterOp | CreateMapOp | CreateListOp;
|
|
134
212
|
declare type UpdateObjectOp = {
|
|
@@ -169,7 +247,7 @@ declare type CreateRegisterOp = {
|
|
|
169
247
|
type: OpType.CreateRegister;
|
|
170
248
|
parentId: string;
|
|
171
249
|
parentKey: string;
|
|
172
|
-
data:
|
|
250
|
+
data: Json;
|
|
173
251
|
};
|
|
174
252
|
declare type DeleteCrdtOp = {
|
|
175
253
|
opId?: string;
|