@liveblocks/core 1.5.0-test1 → 1.5.0-test3

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.mjs CHANGED
@@ -6,7 +6,7 @@ var __export = (target, all) => {
6
6
 
7
7
  // src/version.ts
8
8
  var PKG_NAME = "@liveblocks/core";
9
- var PKG_VERSION = "1.5.0-test1";
9
+ var PKG_VERSION = "1.5.0-test3";
10
10
  var PKG_FORMAT = "esm";
11
11
 
12
12
  // src/dupe-detection.ts
@@ -585,8 +585,8 @@ function tryParseJson(rawMessage) {
585
585
  return void 0;
586
586
  }
587
587
  }
588
- function deepClone(items) {
589
- return JSON.parse(JSON.stringify(items));
588
+ function deepClone(value) {
589
+ return JSON.parse(JSON.stringify(value));
590
590
  }
591
591
  function b64decode(b64value) {
592
592
  try {
@@ -673,6 +673,9 @@ function shouldRetryWithoutReauth(code) {
673
673
  }
674
674
 
675
675
  // src/connection.ts
676
+ function isIdle(status) {
677
+ return status === "initial" || status === "disconnected";
678
+ }
676
679
  function newToLegacyStatus(status) {
677
680
  switch (status) {
678
681
  case "connecting":
@@ -701,6 +704,7 @@ function toNewConnectionStatus(machine) {
701
704
  case "@auth.backoff":
702
705
  case "@connecting.busy":
703
706
  case "@connecting.backoff":
707
+ case "@idle.zombie":
704
708
  return machine.context.successCount > 0 ? "reconnecting" : "connecting";
705
709
  case "@idle.failed":
706
710
  return "disconnected";
@@ -842,7 +846,7 @@ function createConnectionStateMachine(delegates, options) {
842
846
  socket: null,
843
847
  backoffDelay: RESET_DELAY
844
848
  };
845
- const machine = new FSM(initialContext).addState("@idle.initial").addState("@idle.failed").addState("@auth.busy").addState("@auth.backoff").addState("@connecting.busy").addState("@connecting.backoff").addState("@ok.connected").addState("@ok.awaiting-pong");
849
+ const machine = new FSM(initialContext).addState("@idle.initial").addState("@idle.failed").addState("@idle.zombie").addState("@auth.busy").addState("@auth.backoff").addState("@connecting.busy").addState("@connecting.backoff").addState("@ok.connected").addState("@ok.awaiting-pong");
846
850
  machine.addTransitions("*", {
847
851
  RECONNECT: {
848
852
  target: "@auth.backoff",
@@ -1052,11 +1056,20 @@ function createConnectionStateMachine(delegates, options) {
1052
1056
  ctx.socket?.send("ping");
1053
1057
  }
1054
1058
  };
1055
- machine.addTimedTransition("@ok.connected", HEARTBEAT_INTERVAL, sendHeartbeat).addTransitions("@ok.connected", {
1056
- NAVIGATOR_OFFLINE: sendHeartbeat,
1059
+ const maybeHeartbeat = () => {
1060
+ const doc = typeof document !== "undefined" ? document : void 0;
1061
+ const canZombie = doc?.visibilityState === "hidden" && delegates.canZombie();
1062
+ return canZombie ? "@idle.zombie" : sendHeartbeat;
1063
+ };
1064
+ machine.addTimedTransition("@ok.connected", HEARTBEAT_INTERVAL, maybeHeartbeat).addTransitions("@ok.connected", {
1065
+ NAVIGATOR_OFFLINE: maybeHeartbeat,
1057
1066
  // Don't take the browser's word for it when it says it's offline. Do a ping/pong to make sure.
1058
1067
  WINDOW_GOT_FOCUS: sendHeartbeat
1059
1068
  });
1069
+ machine.addTransitions("@idle.zombie", {
1070
+ WINDOW_GOT_FOCUS: "@connecting.backoff"
1071
+ // When in zombie state, the client will try to wake up automatically when the window regains focus
1072
+ });
1060
1073
  machine.onEnter("@ok.*", (ctx) => {
1061
1074
  ctx.patch({ successCount: ctx.successCount + 1 });
1062
1075
  const timerID = setTimeout(
@@ -1287,6 +1300,12 @@ function createAuthManager(authOptions) {
1287
1300
  const tokens = [];
1288
1301
  const expiryTimes = [];
1289
1302
  const requestPromises = /* @__PURE__ */ new Map();
1303
+ function reset() {
1304
+ seenTokens.clear();
1305
+ tokens.length = 0;
1306
+ expiryTimes.length = 0;
1307
+ requestPromises.clear();
1308
+ }
1290
1309
  function hasCorrespondingScopes(requestedScope, scopes) {
1291
1310
  if (requestedScope === "comments:read") {
1292
1311
  return scopes.includes("comments:read" /* CommentsRead */) || scopes.includes("comments:write" /* CommentsWrite */) || scopes.includes("room:read" /* Read */) || scopes.includes("room:write" /* Write */);
@@ -1322,7 +1341,7 @@ function createAuthManager(authOptions) {
1322
1341
  if (authentication.type === "private") {
1323
1342
  if (fetcher === void 0) {
1324
1343
  throw new StopRetrying(
1325
- "To use Liveblocks client in a non-dom environment with a url as auth endpoint, you need to provide a fetch polyfill."
1344
+ "To use Liveblocks client in a non-DOM environment with a url as auth endpoint, you need to provide a fetch polyfill."
1326
1345
  );
1327
1346
  }
1328
1347
  const response = await fetchAuthEndpoint(fetcher, authentication.url, {
@@ -1386,6 +1405,7 @@ function createAuthManager(authOptions) {
1386
1405
  }
1387
1406
  }
1388
1407
  return {
1408
+ reset,
1389
1409
  getAuthValue
1390
1410
  };
1391
1411
  }
@@ -1467,6 +1487,9 @@ async function fetchAuthEndpoint(fetch2, endpoint, body) {
1467
1487
  return { token };
1468
1488
  }
1469
1489
 
1490
+ // src/constants.ts
1491
+ var DEFAULT_BASE_URL = "https://api.liveblocks.io";
1492
+
1470
1493
  // src/devtools/bridge.ts
1471
1494
  var _bridgeActive = false;
1472
1495
  function activateBridge(allowed) {
@@ -1718,7 +1741,7 @@ function getAuthBearerHeaderFromAuthValue(authValue) {
1718
1741
  return authValue.token.raw;
1719
1742
  }
1720
1743
  }
1721
- function createCommentsApi(roomId, getAuthValue, { serverEndpoint }) {
1744
+ function createCommentsApi(roomId, getAuthValue, config) {
1722
1745
  async function fetchJson(endpoint, options) {
1723
1746
  const response = await fetchApi(roomId, endpoint, options);
1724
1747
  if (!response.ok) {
@@ -1745,9 +1768,10 @@ function createCommentsApi(roomId, getAuthValue, { serverEndpoint }) {
1745
1768
  }
1746
1769
  async function fetchApi(roomId2, endpoint, options) {
1747
1770
  const authValue = await getAuthValue();
1748
- const url = `${serverEndpoint}/c/rooms/${encodeURIComponent(
1749
- roomId2
1750
- )}${endpoint}`;
1771
+ const url = new URL(
1772
+ `/v2/c/rooms/${encodeURIComponent(roomId2)}${endpoint}`,
1773
+ config.baseUrl
1774
+ ).toString();
1751
1775
  return await fetch(url, {
1752
1776
  ...options,
1753
1777
  headers: {
@@ -2309,6 +2333,9 @@ var LiveRegister = class _LiveRegister extends AbstractCrdt {
2309
2333
  _toImmutable() {
2310
2334
  return this._data;
2311
2335
  }
2336
+ clone() {
2337
+ return deepClone(this.data);
2338
+ }
2312
2339
  };
2313
2340
 
2314
2341
  // src/crdts/LiveList.ts
@@ -3252,6 +3279,9 @@ var LiveList = class _LiveList extends AbstractCrdt {
3252
3279
  const result = this._items.map((node) => node.toImmutable());
3253
3280
  return process.env.NODE_ENV === "production" ? result : Object.freeze(result);
3254
3281
  }
3282
+ clone() {
3283
+ return new _LiveList(this._items.map((item) => item.clone()));
3284
+ }
3255
3285
  };
3256
3286
  var LiveListIterator = class {
3257
3287
  constructor(items) {
@@ -3335,10 +3365,10 @@ var LiveMap = class _LiveMap extends AbstractCrdt {
3335
3365
  this.unacknowledgedSet = /* @__PURE__ */ new Map();
3336
3366
  if (entries2) {
3337
3367
  const mappedEntries = [];
3338
- for (const entry of entries2) {
3339
- const value = lsonToLiveNode(entry[1]);
3340
- value._setParentLink(this, entry[0]);
3341
- mappedEntries.push([entry[0], value]);
3368
+ for (const [key, value] of entries2) {
3369
+ const node = lsonToLiveNode(value);
3370
+ node._setParentLink(this, key);
3371
+ mappedEntries.push([key, node]);
3342
3372
  }
3343
3373
  this._map = new Map(mappedEntries);
3344
3374
  } else {
@@ -3669,6 +3699,11 @@ var LiveMap = class _LiveMap extends AbstractCrdt {
3669
3699
  }
3670
3700
  return freeze(result);
3671
3701
  }
3702
+ clone() {
3703
+ return new _LiveMap(
3704
+ Array.from(this._map).map(([key, node]) => [key, node.clone()])
3705
+ );
3706
+ }
3672
3707
  };
3673
3708
 
3674
3709
  // src/crdts/LiveObject.ts
@@ -4179,6 +4214,16 @@ var LiveObject = class _LiveObject extends AbstractCrdt {
4179
4214
  }
4180
4215
  return process.env.NODE_ENV === "production" ? result : Object.freeze(result);
4181
4216
  }
4217
+ clone() {
4218
+ return new _LiveObject(
4219
+ Object.fromEntries(
4220
+ Array.from(this._map).map(([key, value]) => [
4221
+ key,
4222
+ isLiveStructure(value) ? value.clone() : deepClone(value)
4223
+ ])
4224
+ )
4225
+ );
4226
+ }
4182
4227
  };
4183
4228
 
4184
4229
  // src/crdts/liveblocks-helpers.ts
@@ -4264,6 +4309,9 @@ function isLiveObject(value) {
4264
4309
  function isLiveRegister(value) {
4265
4310
  return value instanceof LiveRegister;
4266
4311
  }
4312
+ function cloneLson(value) {
4313
+ return value === void 0 ? void 0 : isLiveStructure(value) ? value.clone() : deepClone(value);
4314
+ }
4267
4315
  function liveNodeToLson(obj) {
4268
4316
  if (obj instanceof LiveRegister) {
4269
4317
  return obj.data;
@@ -4698,10 +4746,40 @@ function userToTreeNode(key, user) {
4698
4746
  payload: user
4699
4747
  };
4700
4748
  }
4749
+ function installBackgroundTabSpy() {
4750
+ const doc = typeof document !== "undefined" ? document : void 0;
4751
+ const inBackgroundSince = { current: null };
4752
+ function onVisibilityChange() {
4753
+ if (doc?.visibilityState === "hidden") {
4754
+ inBackgroundSince.current = inBackgroundSince.current ?? Date.now();
4755
+ } else {
4756
+ inBackgroundSince.current = null;
4757
+ }
4758
+ }
4759
+ doc?.addEventListener("visibilitychange", onVisibilityChange);
4760
+ const unsub = () => {
4761
+ doc?.removeEventListener("visibilitychange", onVisibilityChange);
4762
+ };
4763
+ return [inBackgroundSince, unsub];
4764
+ }
4701
4765
  function createRoom(options, config) {
4702
4766
  const initialPresence = typeof options.initialPresence === "function" ? options.initialPresence(config.roomId) : options.initialPresence;
4703
4767
  const initialStorage = typeof options.initialStorage === "function" ? options.initialStorage(config.roomId) : options.initialStorage;
4704
- const delegates = config.delegates;
4768
+ const [inBackgroundSince, uninstallBgTabSpy] = installBackgroundTabSpy();
4769
+ const delegates = {
4770
+ ...config.delegates,
4771
+ // A connection is allowed to go into "zombie state" only if all of the
4772
+ // following conditions apply:
4773
+ //
4774
+ // - The `backgroundKeepAliveTimeout` client option is configured
4775
+ // - The browser window has been in the background for at least
4776
+ // `backgroundKeepAliveTimeout` milliseconds
4777
+ // - There are no pending changes
4778
+ //
4779
+ canZombie() {
4780
+ return config.backgroundKeepAliveTimeout !== void 0 && inBackgroundSince.current !== null && Date.now() > inBackgroundSince.current + config.backgroundKeepAliveTimeout && getStorageStatus() !== "synchronizing";
4781
+ }
4782
+ };
4705
4783
  const managedSocket = new ManagedSocket(
4706
4784
  delegates,
4707
4785
  config.enableDebugLogging
@@ -4764,7 +4842,6 @@ function createRoom(options, config) {
4764
4842
  }
4765
4843
  batchUpdates(() => {
4766
4844
  eventHub.status.notify(newStatus);
4767
- eventHub.connection.notify(newToLegacyStatus(newStatus));
4768
4845
  notifySelfChanged(doNotBatchUpdates);
4769
4846
  });
4770
4847
  }
@@ -4901,15 +4978,13 @@ function createRoom(options, config) {
4901
4978
  comments: makeEventSource()
4902
4979
  };
4903
4980
  async function httpSend(authTokenOrPublicApiKey, roomId, nonce, messages) {
4904
- const baseUrl = new URL(config.liveblocksServer);
4905
- baseUrl.protocol = "https";
4906
4981
  const url = new URL(
4907
4982
  `/v2/c/rooms/${encodeURIComponent(roomId)}/send-message`,
4908
- baseUrl
4909
- );
4983
+ config.baseUrl
4984
+ ).toString();
4910
4985
  const fetcher = config.polyfills?.fetch || /* istanbul ignore next */
4911
4986
  fetch;
4912
- return fetcher(url.toString(), {
4987
+ return fetcher(url, {
4913
4988
  method: "POST",
4914
4989
  headers: {
4915
4990
  "Content-Type": "application/json",
@@ -4990,7 +5065,7 @@ function createRoom(options, config) {
4990
5065
  const stackSizeBefore = context.undoStack.length;
4991
5066
  for (const key in context.initialStorage) {
4992
5067
  if (context.root.get(key) === void 0) {
4993
- context.root.set(key, context.initialStorage[key]);
5068
+ context.root.set(key, cloneLson(context.initialStorage[key]));
4994
5069
  }
4995
5070
  }
4996
5071
  context.undoStack.length = stackSizeBefore;
@@ -5021,25 +5096,23 @@ function createRoom(options, config) {
5021
5096
  _addToRealUndoStack(historyOps, batchedUpdatesWrapper);
5022
5097
  }
5023
5098
  }
5024
- function notify({
5025
- storageUpdates = /* @__PURE__ */ new Map(),
5026
- presence = false,
5027
- others: otherEvents = []
5028
- }, batchedUpdatesWrapper) {
5099
+ function notify(updates, batchedUpdatesWrapper) {
5100
+ const storageUpdates = updates.storageUpdates;
5101
+ const othersUpdates = updates.others;
5029
5102
  batchedUpdatesWrapper(() => {
5030
- if (otherEvents.length > 0) {
5103
+ if (othersUpdates !== void 0 && othersUpdates.length > 0) {
5031
5104
  const others = context.others.current;
5032
- for (const event of otherEvents) {
5033
- eventHub.others.notify({ others, event });
5105
+ for (const event of othersUpdates) {
5106
+ eventHub.others.notify({ ...event, others });
5034
5107
  }
5035
5108
  }
5036
- if (presence) {
5109
+ if (updates.presence ?? false) {
5037
5110
  notifySelfChanged(doNotBatchUpdates);
5038
5111
  eventHub.myPresence.notify(context.myPresence.current);
5039
5112
  }
5040
- if (storageUpdates.size > 0) {
5041
- const updates = Array.from(storageUpdates.values());
5042
- eventHub.storage.notify(updates);
5113
+ if (storageUpdates !== void 0 && storageUpdates.size > 0) {
5114
+ const updates2 = Array.from(storageUpdates.values());
5115
+ eventHub.storage.notify(updates2);
5043
5116
  }
5044
5117
  notifyStorageStatus();
5045
5118
  });
@@ -5687,10 +5760,7 @@ ${Array.from(traces).join("\n\n")}`
5687
5760
  (others) => others.map((other, index) => userToTreeNode(`Other ${index}`, other))
5688
5761
  );
5689
5762
  const events = {
5690
- connection: eventHub.connection.observable,
5691
- // Old/deprecated API
5692
5763
  status: eventHub.status.observable,
5693
- // New/recommended API
5694
5764
  lostConnection: eventHub.lostConnection.observable,
5695
5765
  customEvent: eventHub.customEvent.observable,
5696
5766
  others: eventHub.others.observable,
@@ -5705,7 +5775,7 @@ ${Array.from(traces).join("\n\n")}`
5705
5775
  comments: eventHub.comments.observable
5706
5776
  };
5707
5777
  const commentsApi = createCommentsApi(config.roomId, delegates.authenticate, {
5708
- serverEndpoint: "https://api.liveblocks.io/v2"
5778
+ baseUrl: config.baseUrl
5709
5779
  });
5710
5780
  return Object.defineProperty(
5711
5781
  {
@@ -5738,7 +5808,10 @@ ${Array.from(traces).join("\n\n")}`
5738
5808
  connect: () => managedSocket.connect(),
5739
5809
  reconnect: () => managedSocket.reconnect(),
5740
5810
  disconnect: () => managedSocket.disconnect(),
5741
- destroy: () => managedSocket.destroy(),
5811
+ destroy: () => {
5812
+ uninstallBgTabSpy();
5813
+ managedSocket.destroy();
5814
+ },
5742
5815
  // Presence
5743
5816
  updatePresence,
5744
5817
  updateYDoc,
@@ -5809,16 +5882,19 @@ function makeClassicSubscribeFn(events) {
5809
5882
  return events.myPresence.subscribe(callback);
5810
5883
  case "others": {
5811
5884
  const cb = callback;
5812
- return events.others.subscribe(
5813
- ({ others, event }) => cb(others, event)
5814
- );
5885
+ return events.others.subscribe((event) => {
5886
+ const { others, ...internalEvent } = event;
5887
+ return cb(others, internalEvent);
5888
+ });
5815
5889
  }
5816
5890
  case "error":
5817
5891
  return events.error.subscribe(callback);
5818
- case "connection":
5819
- return events.connection.subscribe(
5820
- callback
5892
+ case "connection": {
5893
+ const cb = callback;
5894
+ return events.status.subscribe(
5895
+ (status) => cb(newToLegacyStatus(status))
5821
5896
  );
5897
+ }
5822
5898
  case "status":
5823
5899
  return events.status.subscribe(callback);
5824
5900
  case "lost-connection":
@@ -5870,15 +5946,17 @@ function makeAuthDelegateForRoom(roomId, authManager) {
5870
5946
  return authManager.getAuthValue("room:read", roomId);
5871
5947
  };
5872
5948
  }
5873
- function makeCreateSocketDelegateForRoom(roomId, liveblocksServer, WebSocketPolyfill) {
5949
+ function makeCreateSocketDelegateForRoom(roomId, baseUrl, WebSocketPolyfill) {
5874
5950
  return (authValue) => {
5875
5951
  const ws = WebSocketPolyfill ?? (typeof WebSocket === "undefined" ? void 0 : WebSocket);
5876
5952
  if (ws === void 0) {
5877
5953
  throw new StopRetrying(
5878
- "To use Liveblocks client in a non-dom environment, you need to provide a WebSocket polyfill."
5954
+ "To use Liveblocks client in a non-DOM environment, you need to provide a WebSocket polyfill."
5879
5955
  );
5880
5956
  }
5881
- const url = new URL(liveblocksServer);
5957
+ const url = new URL(baseUrl);
5958
+ url.protocol = url.protocol === "http:" ? "ws" : "wss";
5959
+ url.pathname = "/v7";
5882
5960
  url.searchParams.set("roomId", roomId);
5883
5961
  if (authValue.type === "secret") {
5884
5962
  url.searchParams.set("tok", authValue.token.raw);
@@ -5896,13 +5974,20 @@ function makeCreateSocketDelegateForRoom(roomId, liveblocksServer, WebSocketPoly
5896
5974
  var MIN_THROTTLE = 16;
5897
5975
  var MAX_THROTTLE = 1e3;
5898
5976
  var DEFAULT_THROTTLE = 100;
5977
+ var MIN_BACKGROUND_KEEP_ALIVE_TIMEOUT = 6e4;
5899
5978
  var MIN_LOST_CONNECTION_TIMEOUT = 200;
5900
5979
  var RECOMMENDED_MIN_LOST_CONNECTION_TIMEOUT = 1e3;
5901
5980
  var MAX_LOST_CONNECTION_TIMEOUT = 3e4;
5902
5981
  var DEFAULT_LOST_CONNECTION_TIMEOUT = 5e3;
5903
- function getServerFromClientOptions(clientOptions) {
5904
- const rawOptions = clientOptions;
5905
- return typeof rawOptions.liveblocksServer === "string" ? rawOptions.liveblocksServer : "wss://api.liveblocks.io/v7";
5982
+ function getBaseUrlFromClientOptions(clientOptions) {
5983
+ if ("liveblocksServer" in clientOptions) {
5984
+ throw new Error("Client option no longer supported");
5985
+ }
5986
+ if (typeof clientOptions.baseUrl === "string" && clientOptions.baseUrl.startsWith("http")) {
5987
+ return clientOptions.baseUrl;
5988
+ } else {
5989
+ return DEFAULT_BASE_URL;
5990
+ }
5906
5991
  }
5907
5992
  function createClient(options) {
5908
5993
  const clientOptions = options;
@@ -5910,6 +5995,9 @@ function createClient(options) {
5910
5995
  const lostConnectionTimeout = getLostConnectionTimeout(
5911
5996
  clientOptions.lostConnectionTimeout ?? DEFAULT_LOST_CONNECTION_TIMEOUT
5912
5997
  );
5998
+ const backgroundKeepAliveTimeout = getBackgroundKeepAliveTimeout(
5999
+ clientOptions.backgroundKeepAliveTimeout
6000
+ );
5913
6001
  const authManager = createAuthManager(options);
5914
6002
  const roomsById = /* @__PURE__ */ new Map();
5915
6003
  function teardownRoom(room) {
@@ -5945,6 +6033,7 @@ function createClient(options) {
5945
6033
  options2.initialPresence === null || options2.initialPresence === void 0,
5946
6034
  "Please provide an initial presence value for the current user when entering the room."
5947
6035
  );
6036
+ const baseUrl = getBaseUrlFromClientOptions(clientOptions);
5948
6037
  const newRoom = createRoom(
5949
6038
  {
5950
6039
  initialPresence: options2.initialPresence ?? {},
@@ -5954,18 +6043,19 @@ function createClient(options) {
5954
6043
  roomId,
5955
6044
  throttleDelay,
5956
6045
  lostConnectionTimeout,
6046
+ backgroundKeepAliveTimeout,
5957
6047
  polyfills: clientOptions.polyfills,
5958
6048
  delegates: clientOptions.mockedDelegates ?? {
5959
6049
  createSocket: makeCreateSocketDelegateForRoom(
5960
6050
  roomId,
5961
- getServerFromClientOptions(clientOptions),
6051
+ baseUrl,
5962
6052
  clientOptions.polyfills?.WebSocket
5963
6053
  ),
5964
6054
  authenticate: makeAuthDelegateForRoom(roomId, authManager)
5965
6055
  },
5966
6056
  enableDebugLogging: clientOptions.enableDebugLogging,
5967
6057
  unstable_batchedUpdates: options2?.unstable_batchedUpdates,
5968
- liveblocksServer: getServerFromClientOptions(clientOptions),
6058
+ baseUrl,
5969
6059
  unstable_fallbackToHTTP: !!clientOptions.unstable_fallbackToHTTP
5970
6060
  }
5971
6061
  );
@@ -6004,7 +6094,16 @@ function createClient(options) {
6004
6094
  unsub();
6005
6095
  }
6006
6096
  }
6097
+ function logout() {
6098
+ authManager.reset();
6099
+ for (const { room } of roomsById.values()) {
6100
+ if (!isIdle(room.getStatus())) {
6101
+ room.reconnect();
6102
+ }
6103
+ }
6104
+ }
6007
6105
  return {
6106
+ logout,
6008
6107
  // Old, deprecated APIs
6009
6108
  enter,
6010
6109
  getRoom,
@@ -6014,13 +6113,28 @@ function createClient(options) {
6014
6113
  };
6015
6114
  }
6016
6115
  function checkBounds(option, value, min, max, recommendedMin) {
6017
- if (typeof value !== "number" || value < min || value > max) {
6116
+ if (typeof value !== "number" || value < min || max === void 0 || value > max) {
6018
6117
  throw new Error(
6019
- `${option} should be a number between ${recommendedMin ?? min} and ${max}.`
6118
+ max !== void 0 ? `${option} should be between ${recommendedMin ?? min} and ${max}.` : `${option} should be at least ${recommendedMin ?? min}.`
6020
6119
  );
6021
6120
  }
6022
6121
  return value;
6023
6122
  }
6123
+ function getBackgroundKeepAliveTimeout(value) {
6124
+ if (value === void 0)
6125
+ return void 0;
6126
+ if (typeof document === "undefined") {
6127
+ warn(
6128
+ "Setting backgroundKeepAliveTimeout won't have an effect in a non-DOM environment."
6129
+ );
6130
+ return void 0;
6131
+ }
6132
+ return checkBounds(
6133
+ "backgroundKeepAliveTimeout",
6134
+ value,
6135
+ MIN_BACKGROUND_KEEP_ALIVE_TIMEOUT
6136
+ );
6137
+ }
6024
6138
  function getThrottle(value) {
6025
6139
  return checkBounds("throttle", value, MIN_THROTTLE, MAX_THROTTLE);
6026
6140
  }
@@ -6640,6 +6754,7 @@ export {
6640
6754
  assert,
6641
6755
  assertNever,
6642
6756
  b64decode,
6757
+ cloneLson,
6643
6758
  fancy_console_exports as console,
6644
6759
  createAsyncCache,
6645
6760
  createClient,