@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 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 = JSON.parse(atob(tokenParts[1]));
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
- if (isTokenValid(state.token)) {
1625
- const parsedToken = parseToken(state.token);
1626
- const socket = createWebSocket(state.token);
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.room).then(({ token }) => {
1644
+ return auth(context.roomId).then(({ token: token2 }) => {
1630
1645
  if (state.connection.state !== "authenticating") {
1631
1646
  return;
1632
1647
  }
1633
- const parsedToken = parseToken(token);
1634
- const socket = createWebSocket(token);
1648
+ const parsedToken = parseToken(token2);
1649
+ const socket = createWebSocket(token2);
1635
1650
  authenticationSuccess(parsedToken, socket);
1636
- state.token = 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.room
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 message = JSON.parse(event.data);
2070
- let subMessages = [];
2071
- if (Array.isArray(message)) {
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 subMessage of subMessages) {
2081
- switch (subMessage.type) {
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(subMessage);
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(subMessage);
2122
+ onEvent(message);
2095
2123
  break;
2096
2124
  }
2097
2125
  case ServerMessageType.UserLeft: {
2098
- const event2 = onUserLeftMessage(subMessage);
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(subMessage));
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(subMessage);
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(subMessage.ops, false);
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.room,
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 = JSON.parse(atob(tokenParts[1]));
2576
- if (typeof data.actor !== "number") {
2577
- throw new Error(`Authentication error. Liveblocks could not parse the response of your authentication endpoint`);
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
- return data;
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
- room: roomId,
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 = JSON.parse(atob(tokenParts[1]));
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
- if (isTokenValid(state.token)) {
1625
- const parsedToken = parseToken(state.token);
1626
- const socket = createWebSocket(state.token);
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.room).then(({ token }) => {
1644
+ return auth(context.roomId).then(({ token: token2 }) => {
1630
1645
  if (state.connection.state !== "authenticating") {
1631
1646
  return;
1632
1647
  }
1633
- const parsedToken = parseToken(token);
1634
- const socket = createWebSocket(token);
1648
+ const parsedToken = parseToken(token2);
1649
+ const socket = createWebSocket(token2);
1635
1650
  authenticationSuccess(parsedToken, socket);
1636
- state.token = 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.room
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 message = JSON.parse(event.data);
2070
- let subMessages = [];
2071
- if (Array.isArray(message)) {
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 subMessage of subMessages) {
2081
- switch (subMessage.type) {
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(subMessage);
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(subMessage);
2122
+ onEvent(message);
2095
2123
  break;
2096
2124
  }
2097
2125
  case ServerMessageType.UserLeft: {
2098
- const event2 = onUserLeftMessage(subMessage);
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(subMessage));
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(subMessage);
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(subMessage.ops, false);
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.room,
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 = JSON.parse(atob(tokenParts[1]));
2576
- if (typeof data.actor !== "number") {
2577
- throw new Error(`Authentication error. Liveblocks could not parse the response of your authentication endpoint`);
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
- return data;
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
- room: roomId,
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 = JSON.parse(atob(tokenParts[1]));
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
- if (isTokenValid(state.token)) {
2465
- var parsedToken = parseToken(state.token);
2466
- var socket = createWebSocket(state.token);
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.room).then(function (_ref2) {
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.room
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 message = JSON.parse(event.data);
3076
- var subMessages = [];
3114
+ var messages = parseServerMessages(event.data);
3077
3115
 
3078
- if (Array.isArray(message)) {
3079
- subMessages = message;
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(subMessages), _step9; !(_step9 = _iterator9()).done;) {
3090
- var subMessage = _step9.value;
3125
+ for (var _iterator9 = _createForOfIteratorHelperLoose(messages), _step9; !(_step9 = _iterator9()).done;) {
3126
+ var message = _step9.value;
3091
3127
 
3092
- switch (subMessage.type) {
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(subMessage);
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(subMessage);
3148
+ onEvent(message);
3113
3149
  break;
3114
3150
  }
3115
3151
 
3116
3152
  case ServerMessageType.UserLeft:
3117
3153
  {
3118
- var _event = onUserLeftMessage(subMessage);
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(subMessage));
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(subMessage);
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(subMessage.ops, false);
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.room,
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 = JSON.parse(atob(tokenParts[1]));
3792
+ var data = parseJson(atob(tokenParts[1]));
3757
3793
 
3758
- if (typeof data.actor !== "number") {
3759
- throw new Error("Authentication error. Liveblocks could not parse the response of your authentication endpoint");
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
- return data;
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
- room: roomId,
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?: any;
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
- info?: string;
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: any;
250
+ data: Json;
173
251
  };
174
252
  declare type DeleteCrdtOp = {
175
253
  opId?: string;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@liveblocks/client",
3
- "version": "0.16.0",
3
+ "version": "0.16.1",
4
4
  "description": "A client that lets you interact with Liveblocks servers.",
5
5
  "main": "./lib/index.js",
6
6
  "types": "./lib/index.d.ts",