@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 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 = LiveMapUpdates<string, Lson> | LiveObjectUpdates<LsonObject> | LiveListUpdates<Lson>;
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.8"
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
- authenticate(auth, createWebSocket) {
3385
+ authenticateAndConnect(auth, createWebSocket) {
3384
3386
  const prevToken = context.token;
3385
3387
  if (prevToken !== null && !isTokenExpired(prevToken.parsed)) {
3386
- const socket = createWebSocket(prevToken.raw);
3387
- authenticationSuccess(prevToken.parsed, socket);
3388
+ const socket = createWebSocket(prevToken);
3389
+ handleAuthSuccess(prevToken.parsed, socket);
3388
3390
  return void 0;
3389
3391
  } else {
3390
- void auth(config.roomId).then(({ token }) => {
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
- authenticationSuccess(parsedToken, socket);
3397
- context.token = { raw: token, parsed: parsedToken };
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(connect, delay),
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 connect() {
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.authenticate(auth, createWebSocket);
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 authenticationSuccess(token, socket) {
3682
- socket.addEventListener("message", onMessage);
3683
- socket.addEventListener("open", onOpen);
3684
- socket.addEventListener("close", onClose);
3685
- socket.addEventListener("error", onError);
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 onVisibilityChange(visibilityState) {
3710
- if (visibilityState === "visible" && context.connection.current.status === "open") {
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 onNavigatorOnline() {
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 onMessage(event) {
3829
+ function handleRawSocketMessage(event) {
3828
3830
  if (event.data === "pong") {
3829
- clearTimeout(context.timers.pongTimeout);
3830
- return;
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 onClose(event) {
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 onError() {
3991
+ function handleSocketError() {
3984
3992
  }
3985
- function onOpen() {
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 disconnect() {
4036
+ function handleDisconnect() {
4029
4037
  if (context.socket) {
4030
- context.socket.removeEventListener("open", onOpen);
4031
- context.socket.removeEventListener("message", onMessage);
4032
- context.socket.removeEventListener("close", onClose);
4033
- context.socket.removeEventListener("error", onError);
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", onOpen);
4053
- context.socket.removeEventListener("message", onMessage);
4054
- context.socket.removeEventListener("close", onClose);
4055
- context.socket.removeEventListener("error", onError);
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
- connect();
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 simulateCloseWebsocket() {
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
- onClose,
4319
- onMessage,
4320
- authenticationSuccess,
4321
- onNavigatorOnline,
4322
- simulateCloseWebsocket,
4323
- simulateSendCloseEvent,
4324
- onVisibilityChange,
4325
- getUndoStack: () => context.undoStack,
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 (token) => {
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.8"
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 (room) => fetchAuthEndpoint(
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 (room) => fetchAuthEndpoint(fetchPolyfill || fetch, authentication.url, {
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 (room) => __async(this, null, function* () {
4500
- const response = yield authentication.callback(room);
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.onNavigatorOnline();
4663
+ room.__internal.send.navigatorOnline();
4624
4664
  }
4625
4665
  });
4626
4666
  }
4627
4667
  if (typeof document !== "undefined") {
4628
4668
  document.addEventListener("visibilitychange", () => {
4629
- for (const [, room] of rooms) {
4630
- room.__internal.onVisibilityChange(document.visibilityState);
4669
+ if (document.visibilityState === "visible") {
4670
+ for (const [, room] of rooms) {
4671
+ room.__internal.send.windowGotFocus();
4672
+ }
4631
4673
  }
4632
4674
  });
4633
4675
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@liveblocks/core",
3
- "version": "1.0.8",
3
+ "version": "1.0.9",
4
4
  "description": "Shared code and foundational internals for Liveblocks",
5
5
  "main": "./dist/index.js",
6
6
  "types": "./dist/index.d.ts",