@liveblocks/core 1.1.0-beta2 → 1.1.0-beta4

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.
Files changed (2) hide show
  1. package/dist/index.js +95 -68
  2. package/package.json +1 -1
package/dist/index.js CHANGED
@@ -157,7 +157,7 @@ var onMessageFromPanel = eventSource.observable;
157
157
  // src/devtools/index.ts
158
158
  var VERSION = true ? (
159
159
  /* istanbul ignore next */
160
- "1.1.0-beta2"
160
+ "1.1.0-beta4"
161
161
  ) : "dev";
162
162
  var _devtoolsSetupHasRun = false;
163
163
  function setupDevTools(getAllRooms) {
@@ -924,10 +924,6 @@ var logPermanentClose = log(
924
924
  1 /* WARN */,
925
925
  "Connection to WebSocket closed permanently. Won't retry."
926
926
  );
927
- function sendHeartbeat(ctx) {
928
- var _a;
929
- (_a = ctx.socket) == null ? void 0 : _a.send("ping");
930
- }
931
927
  function isCloseEvent(error2) {
932
928
  return !(error2 instanceof Error) && error2.type === "close";
933
929
  }
@@ -1168,20 +1164,18 @@ function createConnectionStateMachine(delegates, enableDebugLogging) {
1168
1164
  };
1169
1165
  }
1170
1166
  );
1171
- machine.addTimedTransition("@ok.connected", HEARTBEAT_INTERVAL, {
1167
+ const sendHeartbeat = {
1172
1168
  target: "@ok.awaiting-pong",
1173
- effect: sendHeartbeat
1174
- }).addTransitions("@ok.connected", {
1175
- WINDOW_GOT_FOCUS: { target: "@ok.awaiting-pong", effect: sendHeartbeat }
1176
- });
1177
- const noPongAction = {
1178
- target: "@connecting.busy",
1179
- // Log implicit connection loss and drop the current open socket
1180
- effect: log(
1181
- 1 /* WARN */,
1182
- "Received no pong from server, assume implicit connection loss."
1183
- )
1169
+ effect: (ctx) => {
1170
+ var _a;
1171
+ (_a = ctx.socket) == null ? void 0 : _a.send("ping");
1172
+ }
1184
1173
  };
1174
+ machine.addTimedTransition("@ok.connected", HEARTBEAT_INTERVAL, sendHeartbeat).addTransitions("@ok.connected", {
1175
+ NAVIGATOR_OFFLINE: sendHeartbeat,
1176
+ // Don't take the browser's word for it when it says it's offline. Do a ping/pong to make sure.
1177
+ WINDOW_GOT_FOCUS: sendHeartbeat
1178
+ });
1185
1179
  machine.onEnter("@ok.*", (ctx) => {
1186
1180
  ctx.patch({ successCount: ctx.successCount + 1 });
1187
1181
  const timerID = setTimeout(
@@ -1197,7 +1191,14 @@ function createConnectionStateMachine(delegates, enableDebugLogging) {
1197
1191
  clearTimeout(timerID);
1198
1192
  onMessage.pause();
1199
1193
  };
1200
- }).addTimedTransition("@ok.awaiting-pong", PONG_TIMEOUT, noPongAction).addTransitions("@ok.awaiting-pong", { PONG_TIMEOUT: noPongAction }).addTransitions("@ok.awaiting-pong", { PONG: "@ok.connected" }).addTransitions("@ok.*", {
1194
+ }).addTransitions("@ok.awaiting-pong", { PONG: "@ok.connected" }).addTimedTransition("@ok.awaiting-pong", PONG_TIMEOUT, {
1195
+ target: "@connecting.busy",
1196
+ // Log implicit connection loss and drop the current open socket
1197
+ effect: log(
1198
+ 1 /* WARN */,
1199
+ "Received no pong from server, assume implicit connection loss."
1200
+ )
1201
+ }).addTransitions("@ok.*", {
1201
1202
  // When a socket receives an error, this can cause the closing of the
1202
1203
  // socket, or not. So always check to see if the socket is still OPEN or
1203
1204
  // not. When still OPEN, don't transition.
@@ -1248,7 +1249,10 @@ function createConnectionStateMachine(delegates, enableDebugLogging) {
1248
1249
  const win = typeof window !== "undefined" ? window : void 0;
1249
1250
  const root = win != null ? win : doc;
1250
1251
  machine.onEnter("*", (ctx) => {
1251
- function onBackOnline() {
1252
+ function onNetworkOffline() {
1253
+ machine.send({ type: "NAVIGATOR_OFFLINE" });
1254
+ }
1255
+ function onNetworkBackOnline() {
1252
1256
  machine.send({ type: "NAVIGATOR_ONLINE" });
1253
1257
  }
1254
1258
  function onVisibilityChange() {
@@ -1256,11 +1260,13 @@ function createConnectionStateMachine(delegates, enableDebugLogging) {
1256
1260
  machine.send({ type: "WINDOW_GOT_FOCUS" });
1257
1261
  }
1258
1262
  }
1259
- win == null ? void 0 : win.addEventListener("online", onBackOnline);
1263
+ win == null ? void 0 : win.addEventListener("online", onNetworkBackOnline);
1264
+ win == null ? void 0 : win.addEventListener("offline", onNetworkOffline);
1260
1265
  root == null ? void 0 : root.addEventListener("visibilitychange", onVisibilityChange);
1261
1266
  return () => {
1262
1267
  root == null ? void 0 : root.removeEventListener("visibilitychange", onVisibilityChange);
1263
- win == null ? void 0 : win.removeEventListener("online", onBackOnline);
1268
+ win == null ? void 0 : win.removeEventListener("online", onNetworkBackOnline);
1269
+ win == null ? void 0 : win.removeEventListener("offline", onNetworkOffline);
1264
1270
  teardownSocket(ctx.socket);
1265
1271
  };
1266
1272
  });
@@ -4340,10 +4346,10 @@ function createRoom(options, config) {
4340
4346
  )
4341
4347
  };
4342
4348
  context.idFactory = makeIdFactory(sessionInfo.id);
4343
- if (context.root) {
4344
- context.buffer.messages.push({ type: 200 /* FETCH_STORAGE */ });
4349
+ if (_getStorage$ !== null) {
4350
+ refreshStorage({ flush: false });
4345
4351
  }
4346
- tryFlushing();
4352
+ flushNowOrSoon();
4347
4353
  }
4348
4354
  function onDidDisconnect() {
4349
4355
  clearTimeout(context.buffer.flushTimerID);
@@ -4471,7 +4477,7 @@ function createRoom(options, config) {
4471
4477
  if (message.items.length === 0) {
4472
4478
  throw new Error("Internal error: cannot load storage without items");
4473
4479
  }
4474
- if (context.root) {
4480
+ if (context.root !== void 0) {
4475
4481
  updateRoot(message.items, batchedUpdatesWrapper);
4476
4482
  } else {
4477
4483
  context.root = LiveObject._fromItems(message.items, pool);
@@ -4483,7 +4489,7 @@ function createRoom(options, config) {
4483
4489
  }
4484
4490
  }
4485
4491
  function updateRoot(items, batchedUpdatesWrapper) {
4486
- if (!context.root) {
4492
+ if (context.root === void 0) {
4487
4493
  return;
4488
4494
  }
4489
4495
  const currentItems = /* @__PURE__ */ new Map();
@@ -4681,7 +4687,7 @@ function createRoom(options, config) {
4681
4687
  }
4682
4688
  context.activeBatch.updates.presence = true;
4683
4689
  } else {
4684
- tryFlushing();
4690
+ flushNowOrSoon();
4685
4691
  batchUpdates(() => {
4686
4692
  if (options2 == null ? void 0 : options2.addToHistory) {
4687
4693
  addToUndoStack(
@@ -4768,7 +4774,7 @@ function createRoom(options, config) {
4768
4774
  data: context.me.current,
4769
4775
  targetActor: message.actor
4770
4776
  });
4771
- tryFlushing();
4777
+ flushNowOrSoon();
4772
4778
  const user = context.others.getUser(message.actor);
4773
4779
  return user ? { type: "enter", user } : void 0;
4774
4780
  }
@@ -4854,9 +4860,7 @@ function createRoom(options, config) {
4854
4860
  const unacknowledgedOps = new Map(context.unacknowledgedOps);
4855
4861
  createOrUpdateRootFromMessage(message, doNotBatchUpdates);
4856
4862
  applyAndSendOps(unacknowledgedOps, doNotBatchUpdates);
4857
- if (_resolveInitialStatePromise !== null) {
4858
- _resolveInitialStatePromise();
4859
- }
4863
+ _resolveStoragePromise == null ? void 0 : _resolveStoragePromise();
4860
4864
  notifyStorageStatus();
4861
4865
  eventHub.storageDidLoad.notify();
4862
4866
  break;
@@ -4903,7 +4907,7 @@ ${Array.from(traces).join("\n\n")}`
4903
4907
  notify(updates, doNotBatchUpdates);
4904
4908
  });
4905
4909
  }
4906
- function tryFlushing() {
4910
+ function flushNowOrSoon() {
4907
4911
  const storageOps = context.buffer.storageOperations;
4908
4912
  if (storageOps.length > 0) {
4909
4913
  for (const op of storageOps) {
@@ -4933,7 +4937,7 @@ ${Array.from(traces).join("\n\n")}`
4933
4937
  } else {
4934
4938
  clearTimeout(context.buffer.flushTimerID);
4935
4939
  context.buffer.flushTimerID = setTimeout(
4936
- tryFlushing,
4940
+ flushNowOrSoon,
4937
4941
  config.throttleDelay - elapsedMillis
4938
4942
  );
4939
4943
  }
@@ -4976,24 +4980,32 @@ ${Array.from(traces).join("\n\n")}`
4976
4980
  type: 103 /* BROADCAST_EVENT */,
4977
4981
  event
4978
4982
  });
4979
- tryFlushing();
4983
+ flushNowOrSoon();
4980
4984
  }
4981
4985
  function dispatchOps(ops) {
4982
4986
  context.buffer.storageOperations.push(...ops);
4983
- tryFlushing();
4987
+ flushNowOrSoon();
4988
+ }
4989
+ let _getStorage$ = null;
4990
+ let _resolveStoragePromise = null;
4991
+ function refreshStorage(options2) {
4992
+ const messages = context.buffer.messages;
4993
+ if (!messages.some((msg) => msg.type === 200 /* FETCH_STORAGE */)) {
4994
+ messages.push({ type: 200 /* FETCH_STORAGE */ });
4995
+ }
4996
+ if (options2.flush) {
4997
+ flushNowOrSoon();
4998
+ }
4984
4999
  }
4985
- let _getInitialStatePromise = null;
4986
- let _resolveInitialStatePromise = null;
4987
5000
  function startLoadingStorage() {
4988
- if (_getInitialStatePromise === null) {
4989
- context.buffer.messages.push({ type: 200 /* FETCH_STORAGE */ });
4990
- tryFlushing();
4991
- _getInitialStatePromise = new Promise(
4992
- (resolve) => _resolveInitialStatePromise = resolve
4993
- );
5001
+ if (_getStorage$ === null) {
5002
+ refreshStorage({ flush: true });
5003
+ _getStorage$ = new Promise((resolve) => {
5004
+ _resolveStoragePromise = resolve;
5005
+ });
4994
5006
  notifyStorageStatus();
4995
5007
  }
4996
- return _getInitialStatePromise;
5008
+ return _getStorage$;
4997
5009
  }
4998
5010
  function getStorageSnapshot() {
4999
5011
  const root = context.root;
@@ -5006,7 +5018,7 @@ ${Array.from(traces).join("\n\n")}`
5006
5018
  }
5007
5019
  function getStorage() {
5008
5020
  return __async(this, null, function* () {
5009
- if (context.root) {
5021
+ if (context.root !== void 0) {
5010
5022
  return Promise.resolve({
5011
5023
  root: context.root
5012
5024
  });
@@ -5037,7 +5049,7 @@ ${Array.from(traces).join("\n\n")}`
5037
5049
  context.buffer.storageOperations.push(op);
5038
5050
  }
5039
5051
  }
5040
- tryFlushing();
5052
+ flushNowOrSoon();
5041
5053
  }
5042
5054
  function redo() {
5043
5055
  if (context.activeBatch) {
@@ -5059,7 +5071,7 @@ ${Array.from(traces).join("\n\n")}`
5059
5071
  context.buffer.storageOperations.push(op);
5060
5072
  }
5061
5073
  }
5062
- tryFlushing();
5074
+ flushNowOrSoon();
5063
5075
  }
5064
5076
  function batch(callback) {
5065
5077
  if (context.activeBatch) {
@@ -5091,7 +5103,7 @@ ${Array.from(traces).join("\n\n")}`
5091
5103
  dispatchOps(currentBatch.ops);
5092
5104
  }
5093
5105
  notify(currentBatch.updates, doNotBatchUpdates);
5094
- tryFlushing();
5106
+ flushNowOrSoon();
5095
5107
  }
5096
5108
  });
5097
5109
  return returnValue;
@@ -5107,13 +5119,11 @@ ${Array.from(traces).join("\n\n")}`
5107
5119
  }
5108
5120
  }
5109
5121
  function getStorageStatus() {
5110
- if (_getInitialStatePromise === null) {
5111
- return "not-loaded";
5112
- }
5113
5122
  if (context.root === void 0) {
5114
- return "loading";
5123
+ return _getStorage$ === null ? "not-loaded" : "loading";
5124
+ } else {
5125
+ return context.unacknowledgedOps.size === 0 ? "synchronized" : "synchronizing";
5115
5126
  }
5116
- return context.unacknowledgedOps.size === 0 ? "synchronized" : "synchronizing";
5117
5127
  }
5118
5128
  let _lastStorageStatus = getStorageStatus();
5119
5129
  function notifyStorageStatus() {
@@ -5164,7 +5174,7 @@ ${Array.from(traces).join("\n\n")}`
5164
5174
  send: {
5165
5175
  // These exist only for our E2E testing app
5166
5176
  explicitClose: (event) => managedSocket._privateSendMachineEvent({ type: "EXPLICIT_SOCKET_CLOSE", event }),
5167
- implicitClose: () => managedSocket._privateSendMachineEvent({ type: "PONG_TIMEOUT" })
5177
+ implicitClose: () => managedSocket._privateSendMachineEvent({ type: "NAVIGATOR_OFFLINE" })
5168
5178
  }
5169
5179
  },
5170
5180
  id: config.roomId,
@@ -5301,7 +5311,7 @@ function makeCreateSocketDelegateForRoom(liveblocksServer, WebSocketPolyfill) {
5301
5311
  // @ts-ignore (__PACKAGE_VERSION__ will be injected by the build script)
5302
5312
  true ? (
5303
5313
  /* istanbul ignore next */
5304
- "1.1.0-beta2"
5314
+ "1.1.0-beta4"
5305
5315
  ) : "dev"}`
5306
5316
  );
5307
5317
  };
@@ -5404,20 +5414,28 @@ function fetchAuthEndpoint(fetch2, endpoint, body) {
5404
5414
  var MIN_THROTTLE = 16;
5405
5415
  var MAX_THROTTLE = 1e3;
5406
5416
  var DEFAULT_THROTTLE = 100;
5417
+ var MIN_LOST_CONNECTION_TIMEOUT = 200;
5418
+ var RECOMMENDED_MIN_LOST_CONNECTION_TIMEOUT = 1e3;
5419
+ var MAX_LOST_CONNECTION_TIMEOUT = 3e4;
5420
+ var DEFAULT_LOST_CONNECTION_TIMEOUT = 5e3;
5407
5421
  function getServerFromClientOptions(clientOptions) {
5408
5422
  const rawOptions = clientOptions;
5409
5423
  return typeof rawOptions.liveblocksServer === "string" ? rawOptions.liveblocksServer : "wss://api.liveblocks.io/v6";
5410
5424
  }
5411
5425
  function createClient(options) {
5426
+ var _a, _b;
5412
5427
  const clientOptions = options;
5413
- const throttleDelay = getThrottleDelayFromOptions(clientOptions);
5428
+ const throttleDelay = getThrottle((_a = clientOptions.throttle) != null ? _a : DEFAULT_THROTTLE);
5429
+ const lostConnectionTimeout = getLostConnectionTimeout(
5430
+ (_b = clientOptions.lostConnectionTimeout) != null ? _b : DEFAULT_LOST_CONNECTION_TIMEOUT
5431
+ );
5414
5432
  const rooms = /* @__PURE__ */ new Map();
5415
5433
  function getRoom(roomId) {
5416
5434
  const room = rooms.get(roomId);
5417
5435
  return room ? room : null;
5418
5436
  }
5419
5437
  function enter(roomId, options2) {
5420
- var _a, _b, _c, _d;
5438
+ var _a2, _b2, _c;
5421
5439
  const existingRoom = rooms.get(roomId);
5422
5440
  if (existingRoom !== void 0) {
5423
5441
  return existingRoom;
@@ -5428,13 +5446,13 @@ function createClient(options) {
5428
5446
  );
5429
5447
  const newRoom = createRoom(
5430
5448
  {
5431
- initialPresence: (_a = options2.initialPresence) != null ? _a : {},
5449
+ initialPresence: (_a2 = options2.initialPresence) != null ? _a2 : {},
5432
5450
  initialStorage: options2.initialStorage
5433
5451
  },
5434
5452
  {
5435
5453
  roomId,
5436
5454
  throttleDelay,
5437
- lostConnectionTimeout: (_b = clientOptions.lostConnectionTimeout) != null ? _b : 5e3,
5455
+ lostConnectionTimeout,
5438
5456
  polyfills: clientOptions.polyfills,
5439
5457
  delegates: clientOptions.mockedDelegates,
5440
5458
  enableDebugLogging: clientOptions.enableDebugLogging,
@@ -5451,10 +5469,10 @@ function createClient(options) {
5451
5469
  rooms.set(roomId, newRoom);
5452
5470
  setupDevTools(() => Array.from(rooms.keys()));
5453
5471
  linkDevTools(roomId, newRoom);
5454
- const shouldConnect = (_c = options2.shouldInitiallyConnect) != null ? _c : true;
5472
+ const shouldConnect = (_b2 = options2.shouldInitiallyConnect) != null ? _b2 : true;
5455
5473
  if (shouldConnect) {
5456
5474
  if (typeof atob === "undefined") {
5457
- if (((_d = clientOptions.polyfills) == null ? void 0 : _d.atob) === void 0) {
5475
+ if (((_c = clientOptions.polyfills) == null ? void 0 : _c.atob) === void 0) {
5458
5476
  throw new Error(
5459
5477
  "You need to polyfill atob to use the client in your environment. Please follow the instructions at https://liveblocks.io/docs/errors/liveblocks-client/atob-polyfill"
5460
5478
  );
@@ -5479,16 +5497,25 @@ function createClient(options) {
5479
5497
  leave
5480
5498
  };
5481
5499
  }
5482
- function getThrottleDelayFromOptions(options) {
5483
- if (options.throttle === void 0) {
5484
- return DEFAULT_THROTTLE;
5485
- }
5486
- if (typeof options.throttle !== "number" || options.throttle < MIN_THROTTLE || options.throttle > MAX_THROTTLE) {
5500
+ function checkBounds(option, value, min, max, recommendedMin) {
5501
+ if (typeof value !== "number" || value < min || value > max) {
5487
5502
  throw new Error(
5488
- `throttle should be a number between ${MIN_THROTTLE} and ${MAX_THROTTLE}.`
5503
+ `${option} should be a number between ${recommendedMin != null ? recommendedMin : min} and ${max}.`
5489
5504
  );
5490
5505
  }
5491
- return options.throttle;
5506
+ return value;
5507
+ }
5508
+ function getThrottle(value) {
5509
+ return checkBounds("throttle", value, MIN_THROTTLE, MAX_THROTTLE);
5510
+ }
5511
+ function getLostConnectionTimeout(value) {
5512
+ return checkBounds(
5513
+ "lostConnectionTimeout",
5514
+ value,
5515
+ MIN_LOST_CONNECTION_TIMEOUT,
5516
+ MAX_LOST_CONNECTION_TIMEOUT,
5517
+ RECOMMENDED_MIN_LOST_CONNECTION_TIMEOUT
5518
+ );
5492
5519
  }
5493
5520
  function prepareAuthentication(clientOptions, roomId) {
5494
5521
  const { publicApiKey, authEndpoint } = clientOptions;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@liveblocks/core",
3
- "version": "1.1.0-beta2",
3
+ "version": "1.1.0-beta4",
4
4
  "description": "Shared code and foundational internals for Liveblocks",
5
5
  "main": "./dist/index.js",
6
6
  "types": "./dist/index.d.ts",