@liveblocks/core 2.15.2 → 2.16.0-rc1

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.js 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 = "2.15.2";
9
+ var PKG_VERSION = "2.16.0-rc1";
10
10
  var PKG_FORMAT = "cjs";
11
11
 
12
12
  // src/dupe-detection.ts
@@ -166,13 +166,18 @@ function wrapWithTitle(method) {
166
166
  var warnWithTitle = wrapWithTitle("warn");
167
167
  var errorWithTitle = wrapWithTitle("error");
168
168
 
169
+ // src/lib/guards.ts
170
+ function isPlainObject(blob) {
171
+ return blob !== null && typeof blob === "object" && Object.prototype.toString.call(blob) === "[object Object]";
172
+ }
173
+ function isStartsWithOperator(blob) {
174
+ return isPlainObject(blob) && typeof blob.startsWith === "string";
175
+ }
176
+
169
177
  // src/lib/utils.ts
170
178
  function raise(msg) {
171
179
  throw new Error(msg);
172
180
  }
173
- function isPlainObject(blob) {
174
- return blob !== null && typeof blob === "object" && Object.prototype.toString.call(blob) === "[object Object]";
175
- }
176
181
  function entries(obj) {
177
182
  return Object.entries(obj);
178
183
  }
@@ -254,13 +259,48 @@ function memoizeOnSuccess(factoryFn) {
254
259
  }
255
260
 
256
261
  // src/lib/autoRetry.ts
257
- var HttpError = class extends Error {
258
- constructor(message, status, details) {
262
+ var HttpError = class _HttpError extends Error {
263
+
264
+
265
+ constructor(message, response, details) {
259
266
  super(message);
260
- this.message = message;
261
- this.status = status;
267
+ this.name = "HttpError";
268
+ this.response = response;
262
269
  this.details = details;
263
270
  }
271
+ static async fromResponse(response) {
272
+ let bodyAsText;
273
+ try {
274
+ bodyAsText = await response.text();
275
+ } catch (e2) {
276
+ }
277
+ const bodyAsJson = bodyAsText ? tryParseJson(bodyAsText) : void 0;
278
+ let bodyAsJsonObject;
279
+ if (isPlainObject(bodyAsJson)) {
280
+ bodyAsJsonObject = bodyAsJson;
281
+ }
282
+ let message = "";
283
+ message ||= typeof _optionalChain([bodyAsJsonObject, 'optionalAccess', _2 => _2.message]) === "string" ? bodyAsJsonObject.message : "";
284
+ message ||= typeof _optionalChain([bodyAsJsonObject, 'optionalAccess', _3 => _3.error]) === "string" ? bodyAsJsonObject.error : "";
285
+ if (bodyAsJson === void 0) {
286
+ message ||= bodyAsText || "";
287
+ }
288
+ message ||= response.statusText;
289
+ let path;
290
+ try {
291
+ path = new URL(response.url).pathname;
292
+ } catch (e3) {
293
+ }
294
+ message += path !== void 0 ? ` (got status ${response.status} from ${path})` : ` (got status ${response.status})`;
295
+ const details = bodyAsJsonObject;
296
+ return new _HttpError(message, response, details);
297
+ }
298
+ /**
299
+ * Convenience accessor for response.status.
300
+ */
301
+ get status() {
302
+ return this.response.status;
303
+ }
264
304
  };
265
305
  var DONT_RETRY_4XX = (x) => x instanceof HttpError && x.status >= 400 && x.status < 500;
266
306
  async function autoRetry(promiseFn, maxTries, backoff, shouldStopRetrying = DONT_RETRY_4XX) {
@@ -323,10 +363,15 @@ function makeEventSource() {
323
363
  res(event);
324
364
  }
325
365
  });
326
- }).finally(() => _optionalChain([unsub, 'optionalCall', _2 => _2()]));
366
+ }).finally(() => _optionalChain([unsub, 'optionalCall', _4 => _4()]));
327
367
  }
328
368
  function notify(event) {
329
- _observers.forEach((callback) => callback(event));
369
+ let called = false;
370
+ for (const callback of _observers) {
371
+ callback(event);
372
+ called = true;
373
+ }
374
+ return called;
330
375
  }
331
376
  function count() {
332
377
  return _observers.size;
@@ -367,8 +412,9 @@ function makeBufferableEventSource() {
367
412
  function notifyOrBuffer(event) {
368
413
  if (_buffer !== null) {
369
414
  _buffer.push(event);
415
+ return false;
370
416
  } else {
371
- eventSource2.notify(event);
417
+ return eventSource2.notify(event);
372
418
  }
373
419
  }
374
420
  return {
@@ -508,7 +554,7 @@ var Signal = class extends AbstractSignal {
508
554
  this.#value = "(disposed)";
509
555
  }
510
556
  get() {
511
- _optionalChain([trackedReads, 'optionalAccess', _3 => _3.add, 'call', _4 => _4(this)]);
557
+ _optionalChain([trackedReads, 'optionalAccess', _5 => _5.add, 'call', _6 => _6(this)]);
512
558
  return this.#value;
513
559
  }
514
560
  set(newValue) {
@@ -618,7 +664,7 @@ var DerivedSignal = class _DerivedSignal extends AbstractSignal {
618
664
  if (this.#dirty) {
619
665
  this.#recompute();
620
666
  }
621
- _optionalChain([trackedReads, 'optionalAccess', _5 => _5.add, 'call', _6 => _6(this)]);
667
+ _optionalChain([trackedReads, 'optionalAccess', _7 => _7.add, 'call', _8 => _8(this)]);
622
668
  return this.#prevValue;
623
669
  }
624
670
  /**
@@ -648,7 +694,7 @@ var MutableSignal = class extends AbstractSignal {
648
694
  this.#state = "(disposed)";
649
695
  }
650
696
  get() {
651
- _optionalChain([trackedReads, 'optionalAccess', _7 => _7.add, 'call', _8 => _8(this)]);
697
+ _optionalChain([trackedReads, 'optionalAccess', _9 => _9.add, 'call', _10 => _10(this)]);
652
698
  return this.#state;
653
699
  }
654
700
  /**
@@ -673,32 +719,15 @@ var MutableSignal = class extends AbstractSignal {
673
719
  };
674
720
 
675
721
  // src/lib/stringify.ts
676
- var EXPLICIT_UNDEFINED_PLACEHOLDER = "_explicit_undefined";
677
722
  function replacer(_key, value) {
678
723
  return value !== null && typeof value === "object" && !Array.isArray(value) ? Object.keys(value).sort().reduce((sorted, key) => {
679
724
  sorted[key] = value[key];
680
725
  return sorted;
681
- }, {}) : value === void 0 ? EXPLICIT_UNDEFINED_PLACEHOLDER : value;
682
- }
683
- function reviver(key, value) {
684
- if (!key && value === EXPLICIT_UNDEFINED_PLACEHOLDER) {
685
- return void 0;
686
- }
687
- if (value && typeof value === "object") {
688
- for (const k in value) {
689
- if (value[k] === EXPLICIT_UNDEFINED_PLACEHOLDER) {
690
- Object.defineProperty(value, k, { value: void 0 });
691
- }
692
- }
693
- }
694
- return value;
726
+ }, {}) : value;
695
727
  }
696
728
  function stringify(value) {
697
729
  return JSON.stringify(value, replacer);
698
730
  }
699
- function unstringify(value) {
700
- return JSON.parse(value, reviver);
701
- }
702
731
 
703
732
  // src/lib/batch.ts
704
733
  var DEFAULT_SIZE = 50;
@@ -751,7 +780,7 @@ var Batch = (_class = class {
751
780
  const results = await this.#callback(inputs);
752
781
  this.error = false;
753
782
  calls.forEach((call, index) => {
754
- const result = _optionalChain([results, 'optionalAccess', _9 => _9[index]]);
783
+ const result = _optionalChain([results, 'optionalAccess', _11 => _11[index]]);
755
784
  if (!Array.isArray(results)) {
756
785
  call.reject(new Error("Callback must return an array."));
757
786
  } else if (calls.length !== results.length) {
@@ -928,10 +957,12 @@ function objectToQuery(obj) {
928
957
  }
929
958
  if (isSimpleValue(value)) {
930
959
  keyValuePairs.push([key, value]);
931
- } else if (isValueWithOperator(value)) {
932
- keyValuePairsWithOperator.push([key, value]);
933
- } else if (typeof value === "object" && !("startsWith" in value)) {
934
- indexedKeys.push([key, value]);
960
+ } else if (isPlainObject(value)) {
961
+ if (isStartsWithOperator(value)) {
962
+ keyValuePairsWithOperator.push([key, value]);
963
+ } else {
964
+ indexedKeys.push([key, value]);
965
+ }
935
966
  }
936
967
  });
937
968
  filterList = [
@@ -948,7 +979,7 @@ function objectToQuery(obj) {
948
979
  }
949
980
  if (isSimpleValue(nestedValue)) {
950
981
  nKeyValuePairs.push([formatFilterKey(key, nestedKey), nestedValue]);
951
- } else if (isValueWithOperator(nestedValue)) {
982
+ } else if (isStartsWithOperator(nestedValue)) {
952
983
  nKeyValuePairsWithOperator.push([
953
984
  formatFilterKey(key, nestedKey),
954
985
  nestedValue
@@ -961,9 +992,7 @@ function objectToQuery(obj) {
961
992
  ...getFiltersFromKeyValuePairsWithOperator(nKeyValuePairsWithOperator)
962
993
  ];
963
994
  });
964
- return filterList.map(
965
- ({ key, operator, value }) => formatFilter(key, operator, formatFilterValue(value))
966
- ).join(" AND ");
995
+ return filterList.map(({ key, operator, value }) => `${key}${operator}${quote(value)}`).join(" ");
967
996
  }
968
997
  var getFiltersFromKeyValuePairs = (keyValuePairs) => {
969
998
  const filters = [];
@@ -990,38 +1019,20 @@ var getFiltersFromKeyValuePairsWithOperator = (keyValuePairsWithOperator) => {
990
1019
  return filters;
991
1020
  };
992
1021
  var isSimpleValue = (value) => {
993
- if (typeof value === "string" || typeof value === "number" || typeof value === "boolean") {
994
- return true;
995
- }
996
- return false;
997
- };
998
- var isValueWithOperator = (value) => {
999
- if (typeof value === "object" && value !== null && "startsWith" in value) {
1000
- return true;
1001
- }
1002
- return false;
1003
- };
1004
- var formatFilter = (key, operator, value) => {
1005
- return `${key}${operator}${value}`;
1022
+ return typeof value === "string" || typeof value === "number" || typeof value === "boolean" || value === null;
1006
1023
  };
1007
1024
  var formatFilterKey = (key, nestedKey) => {
1008
1025
  if (nestedKey) {
1009
- return `${key}[${JSON.stringify(nestedKey)}]`;
1026
+ return `${key}[${quote(nestedKey)}]`;
1010
1027
  }
1011
1028
  return key;
1012
1029
  };
1013
- var formatFilterValue = (value) => {
1014
- if (typeof value === "string") {
1015
- if (isStringEmpty(value)) {
1016
- throw new Error("Value cannot be empty");
1017
- }
1018
- return JSON.stringify(value);
1019
- }
1020
- return value.toString();
1021
- };
1022
1030
  var isStringEmpty = (value) => {
1023
1031
  return !value || value.toString().trim() === "";
1024
1032
  };
1033
+ function quote(value) {
1034
+ return typeof value !== "string" || value.includes("'") ? JSON.stringify(value) : `'${value}'`;
1035
+ }
1025
1036
 
1026
1037
  // src/lib/url.ts
1027
1038
  function toURLSearchParams(params) {
@@ -1279,11 +1290,11 @@ function createApiClient({
1279
1290
  `Upload of attachment ${options.attachment.id} was aborted.`,
1280
1291
  "AbortError"
1281
1292
  ) : void 0;
1282
- if (_optionalChain([abortSignal, 'optionalAccess', _10 => _10.aborted])) {
1293
+ if (_optionalChain([abortSignal, 'optionalAccess', _12 => _12.aborted])) {
1283
1294
  throw abortError;
1284
1295
  }
1285
1296
  const handleRetryError = (err) => {
1286
- if (_optionalChain([abortSignal, 'optionalAccess', _11 => _11.aborted])) {
1297
+ if (_optionalChain([abortSignal, 'optionalAccess', _13 => _13.aborted])) {
1287
1298
  throw abortError;
1288
1299
  }
1289
1300
  if (err instanceof HttpError && err.status === 413) {
@@ -1355,7 +1366,7 @@ function createApiClient({
1355
1366
  try {
1356
1367
  uploadId = createMultiPartUpload.uploadId;
1357
1368
  const parts = splitFileIntoParts(attachment.file);
1358
- if (_optionalChain([abortSignal, 'optionalAccess', _12 => _12.aborted])) {
1369
+ if (_optionalChain([abortSignal, 'optionalAccess', _14 => _14.aborted])) {
1359
1370
  throw abortError;
1360
1371
  }
1361
1372
  const batches = chunk(parts, 5);
@@ -1382,7 +1393,7 @@ function createApiClient({
1382
1393
  }
1383
1394
  uploadedParts.push(...await Promise.all(uploadedPartsPromises));
1384
1395
  }
1385
- if (_optionalChain([abortSignal, 'optionalAccess', _13 => _13.aborted])) {
1396
+ if (_optionalChain([abortSignal, 'optionalAccess', _15 => _15.aborted])) {
1386
1397
  throw abortError;
1387
1398
  }
1388
1399
  const sortedUploadedParts = uploadedParts.sort(
@@ -1398,7 +1409,7 @@ function createApiClient({
1398
1409
  { signal: abortSignal }
1399
1410
  );
1400
1411
  } catch (error3) {
1401
- if (uploadId && _optionalChain([error3, 'optionalAccess', _14 => _14.name]) && (error3.name === "AbortError" || error3.name === "TimeoutError")) {
1412
+ if (uploadId && _optionalChain([error3, 'optionalAccess', _16 => _16.name]) && (error3.name === "AbortError" || error3.name === "TimeoutError")) {
1402
1413
  try {
1403
1414
  await httpClient.rawDelete(
1404
1415
  url`/v2/c/rooms/${roomId}/attachments/${attachment.id}/multipart/${uploadId}`,
@@ -1605,7 +1616,7 @@ function createApiClient({
1605
1616
  url`/v2/c/inbox-notifications`,
1606
1617
  await authManager.getAuthValue({ requestedScope: "comments:read" }),
1607
1618
  {
1608
- cursor: _optionalChain([options, 'optionalAccess', _15 => _15.cursor]),
1619
+ cursor: _optionalChain([options, 'optionalAccess', _17 => _17.cursor]),
1609
1620
  limit: PAGE_SIZE
1610
1621
  }
1611
1622
  );
@@ -1689,7 +1700,7 @@ function createApiClient({
1689
1700
  }
1690
1701
  async function getUserThreads_experimental(options) {
1691
1702
  let query;
1692
- if (_optionalChain([options, 'optionalAccess', _16 => _16.query])) {
1703
+ if (_optionalChain([options, 'optionalAccess', _18 => _18.query])) {
1693
1704
  query = objectToQuery(options.query);
1694
1705
  }
1695
1706
  const PAGE_SIZE = 50;
@@ -1697,7 +1708,7 @@ function createApiClient({
1697
1708
  url`/v2/c/threads`,
1698
1709
  await authManager.getAuthValue({ requestedScope: "comments:read" }),
1699
1710
  {
1700
- cursor: _optionalChain([options, 'optionalAccess', _17 => _17.cursor]),
1711
+ cursor: _optionalChain([options, 'optionalAccess', _19 => _19.cursor]),
1701
1712
  query,
1702
1713
  limit: PAGE_SIZE
1703
1714
  }
@@ -1822,7 +1833,7 @@ var HttpClient = class {
1822
1833
  // These headers are default, but can be overriden by custom headers
1823
1834
  "Content-Type": "application/json; charset=utf-8",
1824
1835
  // Possible header overrides
1825
- ..._optionalChain([options, 'optionalAccess', _18 => _18.headers]),
1836
+ ..._optionalChain([options, 'optionalAccess', _20 => _20.headers]),
1826
1837
  // Cannot be overriden by custom headers
1827
1838
  Authorization: `Bearer ${getBearerTokenFromAuthValue(authValue)}`,
1828
1839
  "X-LB-Client": PKG_VERSION || "dev"
@@ -1846,19 +1857,12 @@ var HttpClient = class {
1846
1857
  async #fetch(endpoint, authValue, options, params) {
1847
1858
  const response = await this.#rawFetch(endpoint, authValue, options, params);
1848
1859
  if (!response.ok) {
1849
- let error3;
1850
- try {
1851
- const errorBody = await response.json();
1852
- error3 = new HttpError(errorBody.message, response.status, errorBody);
1853
- } catch (e2) {
1854
- error3 = new HttpError(response.statusText, response.status);
1855
- }
1856
- throw error3;
1860
+ throw await HttpError.fromResponse(response);
1857
1861
  }
1858
1862
  let body;
1859
1863
  try {
1860
1864
  body = await response.json();
1861
- } catch (e3) {
1865
+ } catch (e4) {
1862
1866
  body = {};
1863
1867
  }
1864
1868
  return body;
@@ -2304,7 +2308,7 @@ var FSM = class {
2304
2308
  });
2305
2309
  }
2306
2310
  #getTargetFn(eventName) {
2307
- return _optionalChain([this, 'access', _19 => _19.#allowedTransitions, 'access', _20 => _20.get, 'call', _21 => _21(this.currentState), 'optionalAccess', _22 => _22.get, 'call', _23 => _23(eventName)]);
2311
+ return _optionalChain([this, 'access', _21 => _21.#allowedTransitions, 'access', _22 => _22.get, 'call', _23 => _23(this.currentState), 'optionalAccess', _24 => _24.get, 'call', _25 => _25(eventName)]);
2308
2312
  }
2309
2313
  /**
2310
2314
  * Exits the current state, and executes any necessary cleanup functions.
@@ -2321,7 +2325,7 @@ var FSM = class {
2321
2325
  this.#currentContext.allowPatching((patchableContext) => {
2322
2326
  levels = _nullishCoalesce(levels, () => ( this.#cleanupStack.length));
2323
2327
  for (let i = 0; i < levels; i++) {
2324
- _optionalChain([this, 'access', _24 => _24.#cleanupStack, 'access', _25 => _25.pop, 'call', _26 => _26(), 'optionalCall', _27 => _27(patchableContext)]);
2328
+ _optionalChain([this, 'access', _26 => _26.#cleanupStack, 'access', _27 => _27.pop, 'call', _28 => _28(), 'optionalCall', _29 => _29(patchableContext)]);
2325
2329
  }
2326
2330
  });
2327
2331
  }
@@ -2337,7 +2341,7 @@ var FSM = class {
2337
2341
  this.#currentContext.allowPatching((patchableContext) => {
2338
2342
  for (const pattern of enterPatterns) {
2339
2343
  const enterFn = this.#enterFns.get(pattern);
2340
- const cleanupFn = _optionalChain([enterFn, 'optionalCall', _28 => _28(patchableContext)]);
2344
+ const cleanupFn = _optionalChain([enterFn, 'optionalCall', _30 => _30(patchableContext)]);
2341
2345
  if (typeof cleanupFn === "function") {
2342
2346
  this.#cleanupStack.push(cleanupFn);
2343
2347
  } else {
@@ -2480,6 +2484,7 @@ function toNewConnectionStatus(machine) {
2480
2484
  return machine.context.successCount > 0 ? "reconnecting" : "connecting";
2481
2485
  case "@idle.failed":
2482
2486
  return "disconnected";
2487
+ // istanbul ignore next
2483
2488
  default:
2484
2489
  return assertNever(state, "Unknown state");
2485
2490
  }
@@ -2496,13 +2501,6 @@ var StopRetrying = class extends Error {
2496
2501
  super(reason);
2497
2502
  }
2498
2503
  };
2499
- var LiveblocksError = class extends Error {
2500
- /** @internal */
2501
- constructor(message, code) {
2502
- super(message);
2503
- this.code = code;
2504
- }
2505
- };
2506
2504
  function nextBackoffDelay(currentDelay, delays) {
2507
2505
  return _nullishCoalesce(delays.find((delay) => delay > currentDelay), () => ( delays[delays.length - 1]));
2508
2506
  }
@@ -2612,11 +2610,10 @@ var assign = (patch) => (ctx) => ctx.patch(patch);
2612
2610
  function createConnectionStateMachine(delegates, options) {
2613
2611
  const onMessage = makeBufferableEventSource();
2614
2612
  onMessage.pause();
2615
- const onLiveblocksError = makeEventSource();
2616
- function fireErrorEvent(errmsg, errcode) {
2613
+ const onConnectionError = makeEventSource();
2614
+ function fireErrorEvent(message, code) {
2617
2615
  return () => {
2618
- const err = new LiveblocksError(errmsg, errcode);
2619
- onLiveblocksError.notify(err);
2616
+ onConnectionError.notify({ message, code });
2620
2617
  };
2621
2618
  }
2622
2619
  const initialContext = {
@@ -2738,7 +2735,7 @@ function createConnectionStateMachine(delegates, options) {
2738
2735
  }
2739
2736
  function waitForActorId(event) {
2740
2737
  const serverMsg = tryParseJson(event.data);
2741
- if (_optionalChain([serverMsg, 'optionalAccess', _29 => _29.type]) === 104 /* ROOM_STATE */) {
2738
+ if (_optionalChain([serverMsg, 'optionalAccess', _31 => _31.type]) === 104 /* ROOM_STATE */) {
2742
2739
  didReceiveActor();
2743
2740
  }
2744
2741
  }
@@ -2847,12 +2844,12 @@ function createConnectionStateMachine(delegates, options) {
2847
2844
  const sendHeartbeat = {
2848
2845
  target: "@ok.awaiting-pong",
2849
2846
  effect: (ctx) => {
2850
- _optionalChain([ctx, 'access', _30 => _30.socket, 'optionalAccess', _31 => _31.send, 'call', _32 => _32("ping")]);
2847
+ _optionalChain([ctx, 'access', _32 => _32.socket, 'optionalAccess', _33 => _33.send, 'call', _34 => _34("ping")]);
2851
2848
  }
2852
2849
  };
2853
2850
  const maybeHeartbeat = () => {
2854
2851
  const doc = typeof document !== "undefined" ? document : void 0;
2855
- const canZombie = _optionalChain([doc, 'optionalAccess', _33 => _33.visibilityState]) === "hidden" && delegates.canZombie();
2852
+ const canZombie = _optionalChain([doc, 'optionalAccess', _35 => _35.visibilityState]) === "hidden" && delegates.canZombie();
2856
2853
  return canZombie ? "@idle.zombie" : sendHeartbeat;
2857
2854
  };
2858
2855
  machine.addTimedTransition("@ok.connected", HEARTBEAT_INTERVAL, maybeHeartbeat).addTransitions("@ok.connected", {
@@ -2891,7 +2888,7 @@ function createConnectionStateMachine(delegates, options) {
2891
2888
  // socket, or not. So always check to see if the socket is still OPEN or
2892
2889
  // not. When still OPEN, don't transition.
2893
2890
  EXPLICIT_SOCKET_ERROR: (_, context) => {
2894
- if (_optionalChain([context, 'access', _34 => _34.socket, 'optionalAccess', _35 => _35.readyState]) === 1) {
2891
+ if (_optionalChain([context, 'access', _36 => _36.socket, 'optionalAccess', _37 => _37.readyState]) === 1) {
2895
2892
  return null;
2896
2893
  }
2897
2894
  return {
@@ -2943,17 +2940,17 @@ function createConnectionStateMachine(delegates, options) {
2943
2940
  machine.send({ type: "NAVIGATOR_ONLINE" });
2944
2941
  }
2945
2942
  function onVisibilityChange() {
2946
- if (_optionalChain([doc, 'optionalAccess', _36 => _36.visibilityState]) === "visible") {
2943
+ if (_optionalChain([doc, 'optionalAccess', _38 => _38.visibilityState]) === "visible") {
2947
2944
  machine.send({ type: "WINDOW_GOT_FOCUS" });
2948
2945
  }
2949
2946
  }
2950
- _optionalChain([win, 'optionalAccess', _37 => _37.addEventListener, 'call', _38 => _38("online", onNetworkBackOnline)]);
2951
- _optionalChain([win, 'optionalAccess', _39 => _39.addEventListener, 'call', _40 => _40("offline", onNetworkOffline)]);
2952
- _optionalChain([root, 'optionalAccess', _41 => _41.addEventListener, 'call', _42 => _42("visibilitychange", onVisibilityChange)]);
2947
+ _optionalChain([win, 'optionalAccess', _39 => _39.addEventListener, 'call', _40 => _40("online", onNetworkBackOnline)]);
2948
+ _optionalChain([win, 'optionalAccess', _41 => _41.addEventListener, 'call', _42 => _42("offline", onNetworkOffline)]);
2949
+ _optionalChain([root, 'optionalAccess', _43 => _43.addEventListener, 'call', _44 => _44("visibilitychange", onVisibilityChange)]);
2953
2950
  return () => {
2954
- _optionalChain([root, 'optionalAccess', _43 => _43.removeEventListener, 'call', _44 => _44("visibilitychange", onVisibilityChange)]);
2955
- _optionalChain([win, 'optionalAccess', _45 => _45.removeEventListener, 'call', _46 => _46("online", onNetworkBackOnline)]);
2956
- _optionalChain([win, 'optionalAccess', _47 => _47.removeEventListener, 'call', _48 => _48("offline", onNetworkOffline)]);
2951
+ _optionalChain([root, 'optionalAccess', _45 => _45.removeEventListener, 'call', _46 => _46("visibilitychange", onVisibilityChange)]);
2952
+ _optionalChain([win, 'optionalAccess', _47 => _47.removeEventListener, 'call', _48 => _48("online", onNetworkBackOnline)]);
2953
+ _optionalChain([win, 'optionalAccess', _49 => _49.removeEventListener, 'call', _50 => _50("offline", onNetworkOffline)]);
2957
2954
  teardownSocket(ctx.socket);
2958
2955
  };
2959
2956
  });
@@ -2974,7 +2971,7 @@ function createConnectionStateMachine(delegates, options) {
2974
2971
  didConnect,
2975
2972
  didDisconnect,
2976
2973
  onMessage: onMessage.observable,
2977
- onLiveblocksError: onLiveblocksError.observable
2974
+ onConnectionError: onConnectionError.observable
2978
2975
  }
2979
2976
  };
2980
2977
  }
@@ -2994,7 +2991,7 @@ var ManagedSocket = class {
2994
2991
  getStatus() {
2995
2992
  try {
2996
2993
  return toNewConnectionStatus(this.#machine);
2997
- } catch (e4) {
2994
+ } catch (e5) {
2998
2995
  return "initial";
2999
2996
  }
3000
2997
  }
@@ -3042,7 +3039,7 @@ var ManagedSocket = class {
3042
3039
  * message if this is somehow impossible.
3043
3040
  */
3044
3041
  send(data) {
3045
- const socket = _optionalChain([this, 'access', _49 => _49.#machine, 'access', _50 => _50.context, 'optionalAccess', _51 => _51.socket]);
3042
+ const socket = _optionalChain([this, 'access', _51 => _51.#machine, 'access', _52 => _52.context, 'optionalAccess', _53 => _53.socket]);
3046
3043
  if (socket === null) {
3047
3044
  warn("Cannot send: not connected yet", data);
3048
3045
  } else if (socket.readyState !== 1) {
@@ -3146,7 +3143,7 @@ function createAuthManager(authOptions, onAuthenticate) {
3146
3143
  return void 0;
3147
3144
  }
3148
3145
  async function makeAuthRequest(options) {
3149
- const fetcher = _nullishCoalesce(_optionalChain([authOptions, 'access', _52 => _52.polyfills, 'optionalAccess', _53 => _53.fetch]), () => ( (typeof window === "undefined" ? void 0 : window.fetch)));
3146
+ const fetcher = _nullishCoalesce(_optionalChain([authOptions, 'access', _54 => _54.polyfills, 'optionalAccess', _55 => _55.fetch]), () => ( (typeof window === "undefined" ? void 0 : window.fetch)));
3150
3147
  if (authentication.type === "private") {
3151
3148
  if (fetcher === void 0) {
3152
3149
  throw new StopRetrying(
@@ -3162,7 +3159,7 @@ function createAuthManager(authOptions, onAuthenticate) {
3162
3159
  "The same Liveblocks auth token was issued from the backend before. Caching Liveblocks tokens is not supported."
3163
3160
  );
3164
3161
  }
3165
- _optionalChain([onAuthenticate, 'optionalCall', _54 => _54(parsed.parsed)]);
3162
+ _optionalChain([onAuthenticate, 'optionalCall', _56 => _56(parsed.parsed)]);
3166
3163
  return parsed;
3167
3164
  }
3168
3165
  if (authentication.type === "custom") {
@@ -3170,7 +3167,7 @@ function createAuthManager(authOptions, onAuthenticate) {
3170
3167
  if (response && typeof response === "object") {
3171
3168
  if (typeof response.token === "string") {
3172
3169
  const parsed = parseAuthToken(response.token);
3173
- _optionalChain([onAuthenticate, 'optionalCall', _55 => _55(parsed.parsed)]);
3170
+ _optionalChain([onAuthenticate, 'optionalCall', _57 => _57(parsed.parsed)]);
3174
3171
  return parsed;
3175
3172
  } else if (typeof response.error === "string") {
3176
3173
  const reason = `Authentication failed: ${"reason" in response && typeof response.reason === "string" ? response.reason : "Forbidden"}`;
@@ -3331,7 +3328,7 @@ function sendToPanel(message, options) {
3331
3328
  ...message,
3332
3329
  source: "liveblocks-devtools-client"
3333
3330
  };
3334
- if (!(_optionalChain([options, 'optionalAccess', _56 => _56.force]) || _bridgeActive)) {
3331
+ if (!(_optionalChain([options, 'optionalAccess', _58 => _58.force]) || _bridgeActive)) {
3335
3332
  return;
3336
3333
  }
3337
3334
  window.postMessage(fullMsg, "*");
@@ -3339,7 +3336,7 @@ function sendToPanel(message, options) {
3339
3336
  var eventSource = makeEventSource();
3340
3337
  if (process.env.NODE_ENV !== "production" && typeof window !== "undefined") {
3341
3338
  window.addEventListener("message", (event) => {
3342
- if (event.source === window && _optionalChain([event, 'access', _57 => _57.data, 'optionalAccess', _58 => _58.source]) === "liveblocks-devtools-panel") {
3339
+ if (event.source === window && _optionalChain([event, 'access', _59 => _59.data, 'optionalAccess', _60 => _60.source]) === "liveblocks-devtools-panel") {
3343
3340
  eventSource.notify(event.data);
3344
3341
  } else {
3345
3342
  }
@@ -3360,6 +3357,12 @@ function setupDevTools(getAllRooms) {
3360
3357
  _devtoolsSetupHasRun = true;
3361
3358
  onMessageFromPanel.subscribe((msg) => {
3362
3359
  switch (msg.msg) {
3360
+ // When a devtool panel sends an explicit "connect" message back to this
3361
+ // live running client (in response to the "wake-up-devtools" message,
3362
+ // or when the devtool panel is opened for the first time), it means that it's okay to
3363
+ // start emitting messages.
3364
+ // Before this explicit acknowledgement, any call to sendToPanel() will
3365
+ // be a no-op.
3363
3366
  case "connect": {
3364
3367
  activateBridge(true);
3365
3368
  for (const roomId of getAllRooms()) {
@@ -3475,7 +3478,7 @@ function fullSync(room) {
3475
3478
  msg: "room::sync::full",
3476
3479
  roomId: room.id,
3477
3480
  status: room.getStatus(),
3478
- storage: _nullishCoalesce(_optionalChain([root, 'optionalAccess', _59 => _59.toTreeNode, 'call', _60 => _60("root"), 'access', _61 => _61.payload]), () => ( null)),
3481
+ storage: _nullishCoalesce(_optionalChain([root, 'optionalAccess', _61 => _61.toTreeNode, 'call', _62 => _62("root"), 'access', _63 => _63.payload]), () => ( null)),
3479
3482
  me,
3480
3483
  others
3481
3484
  });
@@ -3500,6 +3503,8 @@ function linkDevTools(roomId, room) {
3500
3503
  // roomChannelListeners registry
3501
3504
  onMessageFromPanel.subscribe((msg) => {
3502
3505
  switch (msg.msg) {
3506
+ // Sent by the devtool panel when it wants to receive the sync stream
3507
+ // for a room
3503
3508
  case "room::subscribe": {
3504
3509
  if (msg.roomId === roomId) {
3505
3510
  startSyncStream(room);
@@ -3897,7 +3902,7 @@ var LiveRegister = class _LiveRegister extends AbstractCrdt {
3897
3902
  return [
3898
3903
  {
3899
3904
  type: 8 /* CREATE_REGISTER */,
3900
- opId: _optionalChain([pool, 'optionalAccess', _62 => _62.generateOpId, 'call', _63 => _63()]),
3905
+ opId: _optionalChain([pool, 'optionalAccess', _64 => _64.generateOpId, 'call', _65 => _65()]),
3901
3906
  id: this._id,
3902
3907
  parentId,
3903
3908
  parentKey,
@@ -4003,7 +4008,7 @@ var LiveList = class _LiveList extends AbstractCrdt {
4003
4008
  const ops = [];
4004
4009
  const op = {
4005
4010
  id: this._id,
4006
- opId: _optionalChain([pool, 'optionalAccess', _64 => _64.generateOpId, 'call', _65 => _65()]),
4011
+ opId: _optionalChain([pool, 'optionalAccess', _66 => _66.generateOpId, 'call', _67 => _67()]),
4007
4012
  type: 2 /* CREATE_LIST */,
4008
4013
  parentId,
4009
4014
  parentKey
@@ -4274,7 +4279,7 @@ var LiveList = class _LiveList extends AbstractCrdt {
4274
4279
  #applyInsertUndoRedo(op) {
4275
4280
  const { id, parentKey: key } = op;
4276
4281
  const child = creationOpToLiveNode(op);
4277
- if (_optionalChain([this, 'access', _66 => _66._pool, 'optionalAccess', _67 => _67.getNode, 'call', _68 => _68(id)]) !== void 0) {
4282
+ if (_optionalChain([this, 'access', _68 => _68._pool, 'optionalAccess', _69 => _69.getNode, 'call', _70 => _70(id)]) !== void 0) {
4278
4283
  return { modified: false };
4279
4284
  }
4280
4285
  child._attach(id, nn(this._pool));
@@ -4282,8 +4287,8 @@ var LiveList = class _LiveList extends AbstractCrdt {
4282
4287
  const existingItemIndex = this._indexOfPosition(key);
4283
4288
  let newKey = key;
4284
4289
  if (existingItemIndex !== -1) {
4285
- const before2 = _optionalChain([this, 'access', _69 => _69.#items, 'access', _70 => _70[existingItemIndex], 'optionalAccess', _71 => _71._parentPos]);
4286
- const after2 = _optionalChain([this, 'access', _72 => _72.#items, 'access', _73 => _73[existingItemIndex + 1], 'optionalAccess', _74 => _74._parentPos]);
4290
+ const before2 = _optionalChain([this, 'access', _71 => _71.#items, 'access', _72 => _72[existingItemIndex], 'optionalAccess', _73 => _73._parentPos]);
4291
+ const after2 = _optionalChain([this, 'access', _74 => _74.#items, 'access', _75 => _75[existingItemIndex + 1], 'optionalAccess', _76 => _76._parentPos]);
4287
4292
  newKey = makePosition(before2, after2);
4288
4293
  child._setParentLink(this, newKey);
4289
4294
  }
@@ -4297,7 +4302,7 @@ var LiveList = class _LiveList extends AbstractCrdt {
4297
4302
  #applySetUndoRedo(op) {
4298
4303
  const { id, parentKey: key } = op;
4299
4304
  const child = creationOpToLiveNode(op);
4300
- if (_optionalChain([this, 'access', _75 => _75._pool, 'optionalAccess', _76 => _76.getNode, 'call', _77 => _77(id)]) !== void 0) {
4305
+ if (_optionalChain([this, 'access', _77 => _77._pool, 'optionalAccess', _78 => _78.getNode, 'call', _79 => _79(id)]) !== void 0) {
4301
4306
  return { modified: false };
4302
4307
  }
4303
4308
  this.#unacknowledgedSets.set(key, nn(op.opId));
@@ -4418,7 +4423,7 @@ var LiveList = class _LiveList extends AbstractCrdt {
4418
4423
  } else {
4419
4424
  this.#items[existingItemIndex]._setParentLink(
4420
4425
  this,
4421
- makePosition(newKey, _optionalChain([this, 'access', _78 => _78.#items, 'access', _79 => _79[existingItemIndex + 1], 'optionalAccess', _80 => _80._parentPos]))
4426
+ makePosition(newKey, _optionalChain([this, 'access', _80 => _80.#items, 'access', _81 => _81[existingItemIndex + 1], 'optionalAccess', _82 => _82._parentPos]))
4422
4427
  );
4423
4428
  const previousIndex = this.#items.indexOf(child);
4424
4429
  child._setParentLink(this, newKey);
@@ -4443,7 +4448,7 @@ var LiveList = class _LiveList extends AbstractCrdt {
4443
4448
  if (existingItemIndex !== -1) {
4444
4449
  this.#items[existingItemIndex]._setParentLink(
4445
4450
  this,
4446
- makePosition(newKey, _optionalChain([this, 'access', _81 => _81.#items, 'access', _82 => _82[existingItemIndex + 1], 'optionalAccess', _83 => _83._parentPos]))
4451
+ makePosition(newKey, _optionalChain([this, 'access', _83 => _83.#items, 'access', _84 => _84[existingItemIndex + 1], 'optionalAccess', _85 => _85._parentPos]))
4447
4452
  );
4448
4453
  }
4449
4454
  child._setParentLink(this, newKey);
@@ -4462,7 +4467,7 @@ var LiveList = class _LiveList extends AbstractCrdt {
4462
4467
  if (existingItemIndex !== -1) {
4463
4468
  this.#items[existingItemIndex]._setParentLink(
4464
4469
  this,
4465
- makePosition(newKey, _optionalChain([this, 'access', _84 => _84.#items, 'access', _85 => _85[existingItemIndex + 1], 'optionalAccess', _86 => _86._parentPos]))
4470
+ makePosition(newKey, _optionalChain([this, 'access', _86 => _86.#items, 'access', _87 => _87[existingItemIndex + 1], 'optionalAccess', _88 => _88._parentPos]))
4466
4471
  );
4467
4472
  }
4468
4473
  child._setParentLink(this, newKey);
@@ -4489,7 +4494,7 @@ var LiveList = class _LiveList extends AbstractCrdt {
4489
4494
  if (existingItemIndex !== -1) {
4490
4495
  this.#items[existingItemIndex]._setParentLink(
4491
4496
  this,
4492
- makePosition(newKey, _optionalChain([this, 'access', _87 => _87.#items, 'access', _88 => _88[existingItemIndex + 1], 'optionalAccess', _89 => _89._parentPos]))
4497
+ makePosition(newKey, _optionalChain([this, 'access', _89 => _89.#items, 'access', _90 => _90[existingItemIndex + 1], 'optionalAccess', _91 => _91._parentPos]))
4493
4498
  );
4494
4499
  }
4495
4500
  child._setParentLink(this, newKey);
@@ -4547,7 +4552,7 @@ var LiveList = class _LiveList extends AbstractCrdt {
4547
4552
  * @param element The element to add to the end of the LiveList.
4548
4553
  */
4549
4554
  push(element) {
4550
- _optionalChain([this, 'access', _90 => _90._pool, 'optionalAccess', _91 => _91.assertStorageIsWritable, 'call', _92 => _92()]);
4555
+ _optionalChain([this, 'access', _92 => _92._pool, 'optionalAccess', _93 => _93.assertStorageIsWritable, 'call', _94 => _94()]);
4551
4556
  return this.insert(element, this.length);
4552
4557
  }
4553
4558
  /**
@@ -4556,7 +4561,7 @@ var LiveList = class _LiveList extends AbstractCrdt {
4556
4561
  * @param index The index at which you want to insert the element.
4557
4562
  */
4558
4563
  insert(element, index) {
4559
- _optionalChain([this, 'access', _93 => _93._pool, 'optionalAccess', _94 => _94.assertStorageIsWritable, 'call', _95 => _95()]);
4564
+ _optionalChain([this, 'access', _95 => _95._pool, 'optionalAccess', _96 => _96.assertStorageIsWritable, 'call', _97 => _97()]);
4560
4565
  if (index < 0 || index > this.#items.length) {
4561
4566
  throw new Error(
4562
4567
  `Cannot insert list item at index "${index}". index should be between 0 and ${this.#items.length}`
@@ -4586,7 +4591,7 @@ var LiveList = class _LiveList extends AbstractCrdt {
4586
4591
  * @param targetIndex The index where the element should be after moving.
4587
4592
  */
4588
4593
  move(index, targetIndex) {
4589
- _optionalChain([this, 'access', _96 => _96._pool, 'optionalAccess', _97 => _97.assertStorageIsWritable, 'call', _98 => _98()]);
4594
+ _optionalChain([this, 'access', _98 => _98._pool, 'optionalAccess', _99 => _99.assertStorageIsWritable, 'call', _100 => _100()]);
4590
4595
  if (targetIndex < 0) {
4591
4596
  throw new Error("targetIndex cannot be less than 0");
4592
4597
  }
@@ -4644,7 +4649,7 @@ var LiveList = class _LiveList extends AbstractCrdt {
4644
4649
  * @param index The index of the element to delete
4645
4650
  */
4646
4651
  delete(index) {
4647
- _optionalChain([this, 'access', _99 => _99._pool, 'optionalAccess', _100 => _100.assertStorageIsWritable, 'call', _101 => _101()]);
4652
+ _optionalChain([this, 'access', _101 => _101._pool, 'optionalAccess', _102 => _102.assertStorageIsWritable, 'call', _103 => _103()]);
4648
4653
  if (index < 0 || index >= this.#items.length) {
4649
4654
  throw new Error(
4650
4655
  `Cannot delete list item at index "${index}". index should be between 0 and ${this.#items.length - 1}`
@@ -4677,7 +4682,7 @@ var LiveList = class _LiveList extends AbstractCrdt {
4677
4682
  }
4678
4683
  }
4679
4684
  clear() {
4680
- _optionalChain([this, 'access', _102 => _102._pool, 'optionalAccess', _103 => _103.assertStorageIsWritable, 'call', _104 => _104()]);
4685
+ _optionalChain([this, 'access', _104 => _104._pool, 'optionalAccess', _105 => _105.assertStorageIsWritable, 'call', _106 => _106()]);
4681
4686
  if (this._pool) {
4682
4687
  const ops = [];
4683
4688
  const reverseOps = [];
@@ -4711,7 +4716,7 @@ var LiveList = class _LiveList extends AbstractCrdt {
4711
4716
  }
4712
4717
  }
4713
4718
  set(index, item) {
4714
- _optionalChain([this, 'access', _105 => _105._pool, 'optionalAccess', _106 => _106.assertStorageIsWritable, 'call', _107 => _107()]);
4719
+ _optionalChain([this, 'access', _107 => _107._pool, 'optionalAccess', _108 => _108.assertStorageIsWritable, 'call', _109 => _109()]);
4715
4720
  if (index < 0 || index >= this.#items.length) {
4716
4721
  throw new Error(
4717
4722
  `Cannot set list item at index "${index}". index should be between 0 and ${this.#items.length - 1}`
@@ -4857,7 +4862,7 @@ var LiveList = class _LiveList extends AbstractCrdt {
4857
4862
  #shiftItemPosition(index, key) {
4858
4863
  const shiftedPosition = makePosition(
4859
4864
  key,
4860
- this.#items.length > index + 1 ? _optionalChain([this, 'access', _108 => _108.#items, 'access', _109 => _109[index + 1], 'optionalAccess', _110 => _110._parentPos]) : void 0
4865
+ this.#items.length > index + 1 ? _optionalChain([this, 'access', _110 => _110.#items, 'access', _111 => _111[index + 1], 'optionalAccess', _112 => _112._parentPos]) : void 0
4861
4866
  );
4862
4867
  this.#items[index]._setParentLink(this, shiftedPosition);
4863
4868
  }
@@ -4982,7 +4987,7 @@ var LiveMap = class _LiveMap extends AbstractCrdt {
4982
4987
  const ops = [];
4983
4988
  const op = {
4984
4989
  id: this._id,
4985
- opId: _optionalChain([pool, 'optionalAccess', _111 => _111.generateOpId, 'call', _112 => _112()]),
4990
+ opId: _optionalChain([pool, 'optionalAccess', _113 => _113.generateOpId, 'call', _114 => _114()]),
4986
4991
  type: 7 /* CREATE_MAP */,
4987
4992
  parentId,
4988
4993
  parentKey
@@ -5117,7 +5122,7 @@ var LiveMap = class _LiveMap extends AbstractCrdt {
5117
5122
  * @param value The value of the element to add. Should be serializable to JSON.
5118
5123
  */
5119
5124
  set(key, value) {
5120
- _optionalChain([this, 'access', _113 => _113._pool, 'optionalAccess', _114 => _114.assertStorageIsWritable, 'call', _115 => _115()]);
5125
+ _optionalChain([this, 'access', _115 => _115._pool, 'optionalAccess', _116 => _116.assertStorageIsWritable, 'call', _117 => _117()]);
5121
5126
  const oldValue = this.#map.get(key);
5122
5127
  if (oldValue) {
5123
5128
  oldValue._detach();
@@ -5163,7 +5168,7 @@ var LiveMap = class _LiveMap extends AbstractCrdt {
5163
5168
  * @returns true if an element existed and has been removed, or false if the element does not exist.
5164
5169
  */
5165
5170
  delete(key) {
5166
- _optionalChain([this, 'access', _116 => _116._pool, 'optionalAccess', _117 => _117.assertStorageIsWritable, 'call', _118 => _118()]);
5171
+ _optionalChain([this, 'access', _118 => _118._pool, 'optionalAccess', _119 => _119.assertStorageIsWritable, 'call', _120 => _120()]);
5167
5172
  const item = this.#map.get(key);
5168
5173
  if (item === void 0) {
5169
5174
  return false;
@@ -5342,7 +5347,7 @@ var LiveObject = class _LiveObject extends AbstractCrdt {
5342
5347
  if (this._id === void 0) {
5343
5348
  throw new Error("Cannot serialize item is not attached");
5344
5349
  }
5345
- const opId = _optionalChain([pool, 'optionalAccess', _119 => _119.generateOpId, 'call', _120 => _120()]);
5350
+ const opId = _optionalChain([pool, 'optionalAccess', _121 => _121.generateOpId, 'call', _122 => _122()]);
5346
5351
  const ops = [];
5347
5352
  const op = {
5348
5353
  type: 4 /* CREATE_OBJECT */,
@@ -5614,7 +5619,7 @@ var LiveObject = class _LiveObject extends AbstractCrdt {
5614
5619
  * @param value The value of the property to add
5615
5620
  */
5616
5621
  set(key, value) {
5617
- _optionalChain([this, 'access', _121 => _121._pool, 'optionalAccess', _122 => _122.assertStorageIsWritable, 'call', _123 => _123()]);
5622
+ _optionalChain([this, 'access', _123 => _123._pool, 'optionalAccess', _124 => _124.assertStorageIsWritable, 'call', _125 => _125()]);
5618
5623
  this.update({ [key]: value });
5619
5624
  }
5620
5625
  /**
@@ -5629,7 +5634,7 @@ var LiveObject = class _LiveObject extends AbstractCrdt {
5629
5634
  * @param key The key of the property to delete
5630
5635
  */
5631
5636
  delete(key) {
5632
- _optionalChain([this, 'access', _124 => _124._pool, 'optionalAccess', _125 => _125.assertStorageIsWritable, 'call', _126 => _126()]);
5637
+ _optionalChain([this, 'access', _126 => _126._pool, 'optionalAccess', _127 => _127.assertStorageIsWritable, 'call', _128 => _128()]);
5633
5638
  const keyAsString = key;
5634
5639
  const oldValue = this.#map.get(keyAsString);
5635
5640
  if (oldValue === void 0) {
@@ -5682,7 +5687,7 @@ var LiveObject = class _LiveObject extends AbstractCrdt {
5682
5687
  * @param patch The object used to overrides properties
5683
5688
  */
5684
5689
  update(patch) {
5685
- _optionalChain([this, 'access', _127 => _127._pool, 'optionalAccess', _128 => _128.assertStorageIsWritable, 'call', _129 => _129()]);
5690
+ _optionalChain([this, 'access', _129 => _129._pool, 'optionalAccess', _130 => _130.assertStorageIsWritable, 'call', _131 => _131()]);
5686
5691
  if (this._pool === void 0 || this._id === void 0) {
5687
5692
  for (const key in patch) {
5688
5693
  const newValue = patch[key];
@@ -6230,6 +6235,83 @@ var ManagedOthers = class {
6230
6235
  }
6231
6236
  };
6232
6237
 
6238
+ // src/types/LiveblocksError.ts
6239
+ var LiveblocksError = class _LiveblocksError extends Error {
6240
+
6241
+ constructor(message, context, cause) {
6242
+ super(message, { cause });
6243
+ this.context = context;
6244
+ this.name = "LiveblocksError";
6245
+ }
6246
+ /** Convenience accessor for error.context.roomId (if available) */
6247
+ get roomId() {
6248
+ return this.context.roomId;
6249
+ }
6250
+ /** @deprecated Prefer using `context.code` instead, to enable type narrowing */
6251
+ get code() {
6252
+ return this.context.code;
6253
+ }
6254
+ /**
6255
+ * Creates a LiveblocksError from a generic error, by attaching Liveblocks
6256
+ * contextual information like room ID, thread ID, etc.
6257
+ */
6258
+ static from(context, cause) {
6259
+ return new _LiveblocksError(
6260
+ defaultMessageFromContext(context),
6261
+ context,
6262
+ cause
6263
+ );
6264
+ }
6265
+ };
6266
+ function defaultMessageFromContext(context) {
6267
+ switch (context.type) {
6268
+ case "ROOM_CONNECTION_ERROR": {
6269
+ switch (context.code) {
6270
+ case 4001:
6271
+ return "Not allowed to connect to the room";
6272
+ case 4005:
6273
+ return "Room is already full";
6274
+ case 4006:
6275
+ return "Kicked out of the room, because the room ID changed";
6276
+ default:
6277
+ return "Could not connect to the room";
6278
+ }
6279
+ }
6280
+ case "CREATE_THREAD_ERROR":
6281
+ return "Could not create new thread";
6282
+ case "DELETE_THREAD_ERROR":
6283
+ return "Could not delete thread";
6284
+ case "EDIT_THREAD_METADATA_ERROR":
6285
+ return "Could not edit thread metadata";
6286
+ case "MARK_THREAD_AS_RESOLVED_ERROR":
6287
+ return "Could not mark thread as resolved";
6288
+ case "MARK_THREAD_AS_UNRESOLVED_ERROR":
6289
+ return "Could not mark thread as unresolved";
6290
+ case "CREATE_COMMENT_ERROR":
6291
+ return "Could not create new comment";
6292
+ case "EDIT_COMMENT_ERROR":
6293
+ return "Could not edit comment";
6294
+ case "DELETE_COMMENT_ERROR":
6295
+ return "Could not delete comment";
6296
+ case "ADD_REACTION_ERROR":
6297
+ return "Could not add reaction";
6298
+ case "REMOVE_REACTION_ERROR":
6299
+ return "Could not remove reaction";
6300
+ case "MARK_INBOX_NOTIFICATION_AS_READ_ERROR":
6301
+ return "Could not mark inbox notification as read";
6302
+ case "DELETE_INBOX_NOTIFICATION_ERROR":
6303
+ return "Could not delete inbox notification";
6304
+ case "MARK_ALL_INBOX_NOTIFICATIONS_AS_READ_ERROR":
6305
+ return "Could not mark all inbox notifications as read";
6306
+ case "DELETE_ALL_INBOX_NOTIFICATIONS_ERROR":
6307
+ return "Could not delete all inbox notifications";
6308
+ case "UPDATE_NOTIFICATION_SETTINGS_ERROR":
6309
+ return "Could not update notification settings";
6310
+ default:
6311
+ return assertNever(context, "Unhandled case");
6312
+ }
6313
+ }
6314
+
6233
6315
  // src/room.ts
6234
6316
  var MAX_SOCKET_MESSAGE_SIZE = 1024 * 1024 - 1024;
6235
6317
  function makeIdFactory(connectionId) {
@@ -6254,15 +6336,15 @@ function installBackgroundTabSpy() {
6254
6336
  const doc = typeof document !== "undefined" ? document : void 0;
6255
6337
  const inBackgroundSince = { current: null };
6256
6338
  function onVisibilityChange() {
6257
- if (_optionalChain([doc, 'optionalAccess', _130 => _130.visibilityState]) === "hidden") {
6339
+ if (_optionalChain([doc, 'optionalAccess', _132 => _132.visibilityState]) === "hidden") {
6258
6340
  inBackgroundSince.current = _nullishCoalesce(inBackgroundSince.current, () => ( Date.now()));
6259
6341
  } else {
6260
6342
  inBackgroundSince.current = null;
6261
6343
  }
6262
6344
  }
6263
- _optionalChain([doc, 'optionalAccess', _131 => _131.addEventListener, 'call', _132 => _132("visibilitychange", onVisibilityChange)]);
6345
+ _optionalChain([doc, 'optionalAccess', _133 => _133.addEventListener, 'call', _134 => _134("visibilitychange", onVisibilityChange)]);
6264
6346
  const unsub = () => {
6265
- _optionalChain([doc, 'optionalAccess', _133 => _133.removeEventListener, 'call', _134 => _134("visibilitychange", onVisibilityChange)]);
6347
+ _optionalChain([doc, 'optionalAccess', _135 => _135.removeEventListener, 'call', _136 => _136("visibilitychange", onVisibilityChange)]);
6266
6348
  };
6267
6349
  return [inBackgroundSince, unsub];
6268
6350
  }
@@ -6394,13 +6476,17 @@ function createRoom(options, config) {
6394
6476
  managedSocket.events.statusDidChange.subscribe(handleConnectionLossEvent);
6395
6477
  managedSocket.events.didConnect.subscribe(onDidConnect);
6396
6478
  managedSocket.events.didDisconnect.subscribe(onDidDisconnect);
6397
- managedSocket.events.onLiveblocksError.subscribe((err) => {
6398
- if (process.env.NODE_ENV !== "production") {
6399
- error2(
6400
- `Connection to websocket server closed. Reason: ${err.message} (code: ${err.code}).`
6401
- );
6479
+ managedSocket.events.onConnectionError.subscribe(({ message, code }) => {
6480
+ const type = "ROOM_CONNECTION_ERROR";
6481
+ const err = new LiveblocksError(message, { type, code, roomId });
6482
+ const didNotify = config.errorEventSource.notify(err);
6483
+ if (!didNotify) {
6484
+ if (process.env.NODE_ENV !== "production") {
6485
+ error2(
6486
+ `Connection to websocket server closed. Reason: ${message} (code: ${code}).`
6487
+ );
6488
+ }
6402
6489
  }
6403
- eventHub.error.notify(err);
6404
6490
  });
6405
6491
  const pool = {
6406
6492
  roomId: config.roomId,
@@ -6443,7 +6529,7 @@ function createRoom(options, config) {
6443
6529
  }
6444
6530
  },
6445
6531
  assertStorageIsWritable: () => {
6446
- const scopes = _optionalChain([context, 'access', _135 => _135.dynamicSessionInfoSig, 'access', _136 => _136.get, 'call', _137 => _137(), 'optionalAccess', _138 => _138.scopes]);
6532
+ const scopes = _optionalChain([context, 'access', _137 => _137.dynamicSessionInfoSig, 'access', _138 => _138.get, 'call', _139 => _139(), 'optionalAccess', _140 => _140.scopes]);
6447
6533
  if (scopes === void 0) {
6448
6534
  return;
6449
6535
  }
@@ -6463,7 +6549,6 @@ function createRoom(options, config) {
6463
6549
  self: makeEventSource(),
6464
6550
  myPresence: makeEventSource(),
6465
6551
  others: makeEventSource(),
6466
- error: makeEventSource(),
6467
6552
  storageBatch: makeEventSource(),
6468
6553
  history: makeEventSource(),
6469
6554
  storageDidLoad: makeEventSource(),
@@ -6499,7 +6584,7 @@ function createRoom(options, config) {
6499
6584
  }
6500
6585
  function sendMessages(messages) {
6501
6586
  const serializedPayload = JSON.stringify(messages);
6502
- const nonce = _optionalChain([context, 'access', _139 => _139.dynamicSessionInfoSig, 'access', _140 => _140.get, 'call', _141 => _141(), 'optionalAccess', _142 => _142.nonce]);
6587
+ const nonce = _optionalChain([context, 'access', _141 => _141.dynamicSessionInfoSig, 'access', _142 => _142.get, 'call', _143 => _143(), 'optionalAccess', _144 => _144.nonce]);
6503
6588
  if (config.unstable_fallbackToHTTP && nonce) {
6504
6589
  const size = new TextEncoder().encode(serializedPayload).length;
6505
6590
  if (size > MAX_SOCKET_MESSAGE_SIZE) {
@@ -6557,7 +6642,7 @@ function createRoom(options, config) {
6557
6642
  } else {
6558
6643
  context.root = LiveObject._fromItems(message.items, pool);
6559
6644
  }
6560
- const canWrite = _nullishCoalesce(_optionalChain([self, 'access', _143 => _143.get, 'call', _144 => _144(), 'optionalAccess', _145 => _145.canWrite]), () => ( true));
6645
+ const canWrite = _nullishCoalesce(_optionalChain([self, 'access', _145 => _145.get, 'call', _146 => _146(), 'optionalAccess', _147 => _147.canWrite]), () => ( true));
6561
6646
  const stackSizeBefore = context.undoStack.length;
6562
6647
  for (const key in context.initialStorage) {
6563
6648
  if (context.root.get(key) === void 0) {
@@ -6760,7 +6845,7 @@ function createRoom(options, config) {
6760
6845
  }
6761
6846
  context.myPresence.patch(patch);
6762
6847
  if (context.activeBatch) {
6763
- if (_optionalChain([options2, 'optionalAccess', _146 => _146.addToHistory])) {
6848
+ if (_optionalChain([options2, 'optionalAccess', _148 => _148.addToHistory])) {
6764
6849
  context.activeBatch.reverseOps.unshift({
6765
6850
  type: "presence",
6766
6851
  data: oldValues
@@ -6769,7 +6854,7 @@ function createRoom(options, config) {
6769
6854
  context.activeBatch.updates.presence = true;
6770
6855
  } else {
6771
6856
  flushNowOrSoon();
6772
- if (_optionalChain([options2, 'optionalAccess', _147 => _147.addToHistory])) {
6857
+ if (_optionalChain([options2, 'optionalAccess', _149 => _149.addToHistory])) {
6773
6858
  addToUndoStack([{ type: "presence", data: oldValues }]);
6774
6859
  }
6775
6860
  notify({ presence: true });
@@ -6942,6 +7027,7 @@ function createRoom(options, config) {
6942
7027
  processInitialStorage(message);
6943
7028
  break;
6944
7029
  }
7030
+ // Write event
6945
7031
  case 201 /* UPDATE_STORAGE */: {
6946
7032
  const applyResult = applyOps(message.ops, false);
6947
7033
  for (const [key, value] of applyResult.updates.storageUpdates) {
@@ -6952,6 +7038,11 @@ function createRoom(options, config) {
6952
7038
  }
6953
7039
  break;
6954
7040
  }
7041
+ // Receiving a RejectedOps message in the client means that the server is no
7042
+ // longer in sync with the client. Trying to synchronize the client again by
7043
+ // rolling back particular Ops may be hard/impossible. It's fine to not try and
7044
+ // accept the out-of-sync reality and throw an error. We look at this kind of bug
7045
+ // as a developer-owned bug. In production, these errors are not expected to happen.
6955
7046
  case 299 /* REJECT_STORAGE_OP */: {
6956
7047
  errorWithTitle(
6957
7048
  "Storage mutation rejection error",
@@ -6960,7 +7051,7 @@ function createRoom(options, config) {
6960
7051
  if (process.env.NODE_ENV !== "production") {
6961
7052
  const traces = /* @__PURE__ */ new Set();
6962
7053
  for (const opId of message.opIds) {
6963
- const trace = _optionalChain([context, 'access', _148 => _148.opStackTraces, 'optionalAccess', _149 => _149.get, 'call', _150 => _150(opId)]);
7054
+ const trace = _optionalChain([context, 'access', _150 => _150.opStackTraces, 'optionalAccess', _151 => _151.get, 'call', _152 => _152(opId)]);
6964
7055
  if (trace) {
6965
7056
  traces.add(trace);
6966
7057
  }
@@ -7093,7 +7184,7 @@ ${Array.from(traces).join("\n\n")}`
7093
7184
  const unacknowledgedOps = new Map(context.unacknowledgedOps);
7094
7185
  createOrUpdateRootFromMessage(message);
7095
7186
  applyAndSendOps(unacknowledgedOps);
7096
- _optionalChain([_resolveStoragePromise, 'optionalCall', _151 => _151()]);
7187
+ _optionalChain([_resolveStoragePromise, 'optionalCall', _153 => _153()]);
7097
7188
  notifyStorageStatus();
7098
7189
  eventHub.storageDidLoad.notify();
7099
7190
  }
@@ -7295,7 +7386,6 @@ ${Array.from(traces).join("\n\n")}`
7295
7386
  others: eventHub.others.observable,
7296
7387
  self: eventHub.self.observable,
7297
7388
  myPresence: eventHub.myPresence.observable,
7298
- error: eventHub.error.observable,
7299
7389
  /** @deprecated */
7300
7390
  storage: eventHub.storageBatch.observable,
7301
7391
  storageBatch: eventHub.storageBatch.observable,
@@ -7315,8 +7405,8 @@ ${Array.from(traces).join("\n\n")}`
7315
7405
  async function getThreads(options2) {
7316
7406
  return httpClient.getThreads({
7317
7407
  roomId,
7318
- query: _optionalChain([options2, 'optionalAccess', _152 => _152.query]),
7319
- cursor: _optionalChain([options2, 'optionalAccess', _153 => _153.cursor])
7408
+ query: _optionalChain([options2, 'optionalAccess', _154 => _154.query]),
7409
+ cursor: _optionalChain([options2, 'optionalAccess', _155 => _155.cursor])
7320
7410
  });
7321
7411
  }
7322
7412
  async function getThread(threadId) {
@@ -7417,7 +7507,7 @@ ${Array.from(traces).join("\n\n")}`
7417
7507
  function getNotificationSettings(options2) {
7418
7508
  return httpClient.getNotificationSettings({
7419
7509
  roomId,
7420
- signal: _optionalChain([options2, 'optionalAccess', _154 => _154.signal])
7510
+ signal: _optionalChain([options2, 'optionalAccess', _156 => _156.signal])
7421
7511
  });
7422
7512
  }
7423
7513
  function updateNotificationSettings(settings) {
@@ -7439,7 +7529,7 @@ ${Array.from(traces).join("\n\n")}`
7439
7529
  {
7440
7530
  [kInternal]: {
7441
7531
  get presenceBuffer() {
7442
- return deepClone(_nullishCoalesce(_optionalChain([context, 'access', _155 => _155.buffer, 'access', _156 => _156.presenceUpdates, 'optionalAccess', _157 => _157.data]), () => ( null)));
7532
+ return deepClone(_nullishCoalesce(_optionalChain([context, 'access', _157 => _157.buffer, 'access', _158 => _158.presenceUpdates, 'optionalAccess', _159 => _159.data]), () => ( null)));
7443
7533
  },
7444
7534
  // prettier-ignore
7445
7535
  get undoStack() {
@@ -7454,9 +7544,9 @@ ${Array.from(traces).join("\n\n")}`
7454
7544
  return context.yjsProvider;
7455
7545
  },
7456
7546
  setYjsProvider(newProvider) {
7457
- _optionalChain([context, 'access', _158 => _158.yjsProvider, 'optionalAccess', _159 => _159.off, 'call', _160 => _160("status", yjsStatusDidChange)]);
7547
+ _optionalChain([context, 'access', _160 => _160.yjsProvider, 'optionalAccess', _161 => _161.off, 'call', _162 => _162("status", yjsStatusDidChange)]);
7458
7548
  context.yjsProvider = newProvider;
7459
- _optionalChain([newProvider, 'optionalAccess', _161 => _161.on, 'call', _162 => _162("status", yjsStatusDidChange)]);
7549
+ _optionalChain([newProvider, 'optionalAccess', _163 => _163.on, 'call', _164 => _164("status", yjsStatusDidChange)]);
7460
7550
  context.yjsProviderDidChange.notify();
7461
7551
  },
7462
7552
  yjsProviderDidChange: context.yjsProviderDidChange.observable,
@@ -7486,13 +7576,17 @@ ${Array.from(traces).join("\n\n")}`
7486
7576
  attachmentUrlsStore: httpClient.getOrCreateAttachmentUrlsStore(roomId)
7487
7577
  },
7488
7578
  id: config.roomId,
7489
- subscribe: makeClassicSubscribeFn(events),
7579
+ subscribe: makeClassicSubscribeFn(
7580
+ config.roomId,
7581
+ events,
7582
+ config.errorEventSource
7583
+ ),
7490
7584
  connect: () => managedSocket.connect(),
7491
7585
  reconnect: () => managedSocket.reconnect(),
7492
7586
  disconnect: () => managedSocket.disconnect(),
7493
7587
  destroy: () => {
7494
7588
  syncSourceForStorage.destroy();
7495
- _optionalChain([context, 'access', _163 => _163.yjsProvider, 'optionalAccess', _164 => _164.off, 'call', _165 => _165("status", yjsStatusDidChange)]);
7589
+ _optionalChain([context, 'access', _165 => _165.yjsProvider, 'optionalAccess', _166 => _166.off, 'call', _167 => _167("status", yjsStatusDidChange)]);
7496
7590
  syncSourceForYjs.destroy();
7497
7591
  uninstallBgTabSpy();
7498
7592
  managedSocket.destroy();
@@ -7555,7 +7649,7 @@ ${Array.from(traces).join("\n\n")}`
7555
7649
  { enumerable: false }
7556
7650
  );
7557
7651
  }
7558
- function makeClassicSubscribeFn(events) {
7652
+ function makeClassicSubscribeFn(roomId, events, errorEvents) {
7559
7653
  function subscribeToLiveStructureDeeply(node, callback) {
7560
7654
  return events.storageBatch.subscribe((updates) => {
7561
7655
  const relatedUpdates = updates.filter(
@@ -7595,8 +7689,13 @@ function makeClassicSubscribeFn(events) {
7595
7689
  return cb(others, internalEvent);
7596
7690
  });
7597
7691
  }
7598
- case "error":
7599
- return events.error.subscribe(callback);
7692
+ case "error": {
7693
+ return errorEvents.subscribe((err) => {
7694
+ if (err.roomId === roomId) {
7695
+ return callback(err);
7696
+ }
7697
+ });
7698
+ }
7600
7699
  case "status":
7601
7700
  return events.status.subscribe(callback);
7602
7701
  case "lost-connection":
@@ -7613,6 +7712,7 @@ function makeClassicSubscribeFn(events) {
7613
7712
  return events.comments.subscribe(
7614
7713
  callback
7615
7714
  );
7715
+ // istanbul ignore next
7616
7716
  default:
7617
7717
  return assertNever(
7618
7718
  first,
@@ -7630,7 +7730,7 @@ function makeClassicSubscribeFn(events) {
7630
7730
  }
7631
7731
  if (isLiveNode(first)) {
7632
7732
  const node = first;
7633
- if (_optionalChain([options, 'optionalAccess', _166 => _166.isDeep])) {
7733
+ if (_optionalChain([options, 'optionalAccess', _168 => _168.isDeep])) {
7634
7734
  const storageCallback = second;
7635
7735
  return subscribeToLiveStructureDeeply(node, storageCallback);
7636
7736
  } else {
@@ -7709,8 +7809,8 @@ function createClient(options) {
7709
7809
  const userId = token.k === "sec-legacy" /* SECRET_LEGACY */ ? token.id : token.uid;
7710
7810
  currentUserId.set(() => userId);
7711
7811
  });
7712
- const fetchPolyfill = _optionalChain([clientOptions, 'access', _167 => _167.polyfills, 'optionalAccess', _168 => _168.fetch]) || /* istanbul ignore next */
7713
- _optionalChain([globalThis, 'access', _169 => _169.fetch, 'optionalAccess', _170 => _170.bind, 'call', _171 => _171(globalThis)]);
7812
+ const fetchPolyfill = _optionalChain([clientOptions, 'access', _169 => _169.polyfills, 'optionalAccess', _170 => _170.fetch]) || /* istanbul ignore next */
7813
+ _optionalChain([globalThis, 'access', _171 => _171.fetch, 'optionalAccess', _172 => _172.bind, 'call', _173 => _173(globalThis)]);
7714
7814
  const httpClient = createApiClient({
7715
7815
  baseUrl,
7716
7816
  fetchPolyfill,
@@ -7761,12 +7861,13 @@ function createClient(options) {
7761
7861
  createSocket: makeCreateSocketDelegateForRoom(
7762
7862
  roomId,
7763
7863
  baseUrl,
7764
- _optionalChain([clientOptions, 'access', _172 => _172.polyfills, 'optionalAccess', _173 => _173.WebSocket])
7864
+ _optionalChain([clientOptions, 'access', _174 => _174.polyfills, 'optionalAccess', _175 => _175.WebSocket])
7765
7865
  ),
7766
7866
  authenticate: makeAuthDelegateForRoom(roomId, authManager)
7767
7867
  })),
7768
7868
  enableDebugLogging: clientOptions.enableDebugLogging,
7769
7869
  baseUrl,
7870
+ errorEventSource: liveblocksErrorSource,
7770
7871
  unstable_fallbackToHTTP: !!clientOptions.unstable_fallbackToHTTP,
7771
7872
  unstable_streamData: !!clientOptions.unstable_streamData,
7772
7873
  roomHttpClient: httpClient,
@@ -7783,7 +7884,7 @@ function createClient(options) {
7783
7884
  const shouldConnect = _nullishCoalesce(options2.autoConnect, () => ( true));
7784
7885
  if (shouldConnect) {
7785
7886
  if (typeof atob === "undefined") {
7786
- if (_optionalChain([clientOptions, 'access', _174 => _174.polyfills, 'optionalAccess', _175 => _175.atob]) === void 0) {
7887
+ if (_optionalChain([clientOptions, 'access', _176 => _176.polyfills, 'optionalAccess', _177 => _177.atob]) === void 0) {
7787
7888
  throw new Error(
7788
7889
  "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"
7789
7890
  );
@@ -7795,7 +7896,7 @@ function createClient(options) {
7795
7896
  return leaseRoom(newRoomDetails);
7796
7897
  }
7797
7898
  function getRoom(roomId) {
7798
- const room = _optionalChain([roomsById, 'access', _176 => _176.get, 'call', _177 => _177(roomId), 'optionalAccess', _178 => _178.room]);
7899
+ const room = _optionalChain([roomsById, 'access', _178 => _178.get, 'call', _179 => _179(roomId), 'optionalAccess', _180 => _180.room]);
7799
7900
  return room ? room : null;
7800
7901
  }
7801
7902
  function logout() {
@@ -7815,7 +7916,7 @@ function createClient(options) {
7815
7916
  const batchedResolveUsers = new Batch(
7816
7917
  async (batchedUserIds) => {
7817
7918
  const userIds = batchedUserIds.flat();
7818
- const users = await _optionalChain([resolveUsers, 'optionalCall', _179 => _179({ userIds })]);
7919
+ const users = await _optionalChain([resolveUsers, 'optionalCall', _181 => _181({ userIds })]);
7819
7920
  warnIfNoResolveUsers();
7820
7921
  return _nullishCoalesce(users, () => ( userIds.map(() => void 0)));
7821
7922
  },
@@ -7833,7 +7934,7 @@ function createClient(options) {
7833
7934
  const batchedResolveRoomsInfo = new Batch(
7834
7935
  async (batchedRoomIds) => {
7835
7936
  const roomIds = batchedRoomIds.flat();
7836
- const roomsInfo = await _optionalChain([resolveRoomsInfo, 'optionalCall', _180 => _180({ roomIds })]);
7937
+ const roomsInfo = await _optionalChain([resolveRoomsInfo, 'optionalCall', _182 => _182({ roomIds })]);
7837
7938
  warnIfNoResolveRoomsInfo();
7838
7939
  return _nullishCoalesce(roomsInfo, () => ( roomIds.map(() => void 0)));
7839
7940
  },
@@ -7849,6 +7950,7 @@ function createClient(options) {
7849
7950
  }
7850
7951
  const syncStatusSources = [];
7851
7952
  const syncStatusSignal = new Signal("synchronized");
7953
+ const liveblocksErrorSource = makeEventSource();
7852
7954
  function getSyncStatus() {
7853
7955
  const status = syncStatusSignal.get();
7854
7956
  return status === "synchronizing" ? status : "synchronized";
@@ -7885,7 +7987,7 @@ function createClient(options) {
7885
7987
  }
7886
7988
  };
7887
7989
  const win = typeof window !== "undefined" ? window : void 0;
7888
- _optionalChain([win, 'optionalAccess', _181 => _181.addEventListener, 'call', _182 => _182("beforeunload", maybePreventClose)]);
7990
+ _optionalChain([win, 'optionalAccess', _183 => _183.addEventListener, 'call', _184 => _184("beforeunload", maybePreventClose)]);
7889
7991
  }
7890
7992
  const client = Object.defineProperty(
7891
7993
  {
@@ -7908,6 +8010,7 @@ function createClient(options) {
7908
8010
  },
7909
8011
  getSyncStatus,
7910
8012
  events: {
8013
+ error: liveblocksErrorSource,
7911
8014
  syncStatus: syncStatusSignal
7912
8015
  },
7913
8016
  // Internal
@@ -7923,7 +8026,14 @@ function createClient(options) {
7923
8026
  httpClient,
7924
8027
  // Type-level helper only, it's effectively only an identity-function at runtime
7925
8028
  as: () => client,
7926
- createSyncSource
8029
+ createSyncSource,
8030
+ emitError: (context, cause) => {
8031
+ const error3 = LiveblocksError.from(context, cause);
8032
+ const didNotify = liveblocksErrorSource.notify(error3);
8033
+ if (!didNotify) {
8034
+ error2(error3.message);
8035
+ }
8036
+ }
7927
8037
  }
7928
8038
  },
7929
8039
  kInternal,
@@ -8002,7 +8112,7 @@ var commentBodyElementsTypes = {
8002
8112
  mention: "inline"
8003
8113
  };
8004
8114
  function traverseCommentBody(body, elementOrVisitor, possiblyVisitor) {
8005
- if (!body || !_optionalChain([body, 'optionalAccess', _183 => _183.content])) {
8115
+ if (!body || !_optionalChain([body, 'optionalAccess', _185 => _185.content])) {
8006
8116
  return;
8007
8117
  }
8008
8118
  const element = typeof elementOrVisitor === "string" ? elementOrVisitor : void 0;
@@ -8012,13 +8122,13 @@ function traverseCommentBody(body, elementOrVisitor, possiblyVisitor) {
8012
8122
  for (const block of body.content) {
8013
8123
  if (type === "all" || type === "block") {
8014
8124
  if (guard(block)) {
8015
- _optionalChain([visitor, 'optionalCall', _184 => _184(block)]);
8125
+ _optionalChain([visitor, 'optionalCall', _186 => _186(block)]);
8016
8126
  }
8017
8127
  }
8018
8128
  if (type === "all" || type === "inline") {
8019
8129
  for (const inline of block.children) {
8020
8130
  if (guard(inline)) {
8021
- _optionalChain([visitor, 'optionalCall', _185 => _185(inline)]);
8131
+ _optionalChain([visitor, 'optionalCall', _187 => _187(inline)]);
8022
8132
  }
8023
8133
  }
8024
8134
  }
@@ -8043,7 +8153,7 @@ async function resolveUsersInCommentBody(body, resolveUsers) {
8043
8153
  userIds
8044
8154
  });
8045
8155
  for (const [index, userId] of userIds.entries()) {
8046
- const user = _optionalChain([users, 'optionalAccess', _186 => _186[index]]);
8156
+ const user = _optionalChain([users, 'optionalAccess', _188 => _188[index]]);
8047
8157
  if (user) {
8048
8158
  resolvedUsers.set(userId, user);
8049
8159
  }
@@ -8170,7 +8280,7 @@ var stringifyCommentBodyPlainElements = {
8170
8280
  text: ({ element }) => element.text,
8171
8281
  link: ({ element }) => _nullishCoalesce(element.text, () => ( element.url)),
8172
8282
  mention: ({ element, user }) => {
8173
- return `@${_nullishCoalesce(_optionalChain([user, 'optionalAccess', _187 => _187.name]), () => ( element.id))}`;
8283
+ return `@${_nullishCoalesce(_optionalChain([user, 'optionalAccess', _189 => _189.name]), () => ( element.id))}`;
8174
8284
  }
8175
8285
  };
8176
8286
  var stringifyCommentBodyHtmlElements = {
@@ -8200,7 +8310,7 @@ var stringifyCommentBodyHtmlElements = {
8200
8310
  return html`<a href="${href}" target="_blank" rel="noopener noreferrer">${_nullishCoalesce(element.text, () => ( element.url))}</a>`;
8201
8311
  },
8202
8312
  mention: ({ element, user }) => {
8203
- return html`<span data-mention>@${_nullishCoalesce(_optionalChain([user, 'optionalAccess', _188 => _188.name]), () => ( element.id))}</span>`;
8313
+ return html`<span data-mention>@${_nullishCoalesce(_optionalChain([user, 'optionalAccess', _190 => _190.name]), () => ( element.id))}</span>`;
8204
8314
  }
8205
8315
  };
8206
8316
  var stringifyCommentBodyMarkdownElements = {
@@ -8230,19 +8340,19 @@ var stringifyCommentBodyMarkdownElements = {
8230
8340
  return markdown`[${_nullishCoalesce(element.text, () => ( element.url))}](${href})`;
8231
8341
  },
8232
8342
  mention: ({ element, user }) => {
8233
- return markdown`@${_nullishCoalesce(_optionalChain([user, 'optionalAccess', _189 => _189.name]), () => ( element.id))}`;
8343
+ return markdown`@${_nullishCoalesce(_optionalChain([user, 'optionalAccess', _191 => _191.name]), () => ( element.id))}`;
8234
8344
  }
8235
8345
  };
8236
8346
  async function stringifyCommentBody(body, options) {
8237
- const format = _nullishCoalesce(_optionalChain([options, 'optionalAccess', _190 => _190.format]), () => ( "plain"));
8238
- const separator = _nullishCoalesce(_optionalChain([options, 'optionalAccess', _191 => _191.separator]), () => ( (format === "markdown" ? "\n\n" : "\n")));
8347
+ const format = _nullishCoalesce(_optionalChain([options, 'optionalAccess', _192 => _192.format]), () => ( "plain"));
8348
+ const separator = _nullishCoalesce(_optionalChain([options, 'optionalAccess', _193 => _193.separator]), () => ( (format === "markdown" ? "\n\n" : "\n")));
8239
8349
  const elements = {
8240
8350
  ...format === "html" ? stringifyCommentBodyHtmlElements : format === "markdown" ? stringifyCommentBodyMarkdownElements : stringifyCommentBodyPlainElements,
8241
- ..._optionalChain([options, 'optionalAccess', _192 => _192.elements])
8351
+ ..._optionalChain([options, 'optionalAccess', _194 => _194.elements])
8242
8352
  };
8243
8353
  const resolvedUsers = await resolveUsersInCommentBody(
8244
8354
  body,
8245
- _optionalChain([options, 'optionalAccess', _193 => _193.resolveUsers])
8355
+ _optionalChain([options, 'optionalAccess', _195 => _195.resolveUsers])
8246
8356
  );
8247
8357
  const blocks = body.content.flatMap((block, blockIndex) => {
8248
8358
  switch (block.type) {
@@ -8533,12 +8643,12 @@ function legacy_patchImmutableNode(state, path, update) {
8533
8643
  }
8534
8644
  const newState = Object.assign({}, state);
8535
8645
  for (const key in update.updates) {
8536
- if (_optionalChain([update, 'access', _194 => _194.updates, 'access', _195 => _195[key], 'optionalAccess', _196 => _196.type]) === "update") {
8646
+ if (_optionalChain([update, 'access', _196 => _196.updates, 'access', _197 => _197[key], 'optionalAccess', _198 => _198.type]) === "update") {
8537
8647
  const val = update.node.get(key);
8538
8648
  if (val !== void 0) {
8539
8649
  newState[key] = lsonToJson(val);
8540
8650
  }
8541
- } else if (_optionalChain([update, 'access', _197 => _197.updates, 'access', _198 => _198[key], 'optionalAccess', _199 => _199.type]) === "delete") {
8651
+ } else if (_optionalChain([update, 'access', _199 => _199.updates, 'access', _200 => _200[key], 'optionalAccess', _201 => _201.type]) === "delete") {
8542
8652
  delete newState[key];
8543
8653
  }
8544
8654
  }
@@ -8599,12 +8709,12 @@ function legacy_patchImmutableNode(state, path, update) {
8599
8709
  }
8600
8710
  const newState = Object.assign({}, state);
8601
8711
  for (const key in update.updates) {
8602
- if (_optionalChain([update, 'access', _200 => _200.updates, 'access', _201 => _201[key], 'optionalAccess', _202 => _202.type]) === "update") {
8712
+ if (_optionalChain([update, 'access', _202 => _202.updates, 'access', _203 => _203[key], 'optionalAccess', _204 => _204.type]) === "update") {
8603
8713
  const value = update.node.get(key);
8604
8714
  if (value !== void 0) {
8605
8715
  newState[key] = lsonToJson(value);
8606
8716
  }
8607
- } else if (_optionalChain([update, 'access', _203 => _203.updates, 'access', _204 => _204[key], 'optionalAccess', _205 => _205.type]) === "delete") {
8717
+ } else if (_optionalChain([update, 'access', _205 => _205.updates, 'access', _206 => _206[key], 'optionalAccess', _207 => _207.type]) === "delete") {
8608
8718
  delete newState[key];
8609
8719
  }
8610
8720
  }
@@ -8675,9 +8785,9 @@ function makePoller(callback, intervalMs, options) {
8675
8785
  const startTime = performance.now();
8676
8786
  const doc = typeof document !== "undefined" ? document : void 0;
8677
8787
  const win = typeof window !== "undefined" ? window : void 0;
8678
- const maxStaleTimeMs = _nullishCoalesce(_optionalChain([options, 'optionalAccess', _206 => _206.maxStaleTimeMs]), () => ( Number.POSITIVE_INFINITY));
8788
+ const maxStaleTimeMs = _nullishCoalesce(_optionalChain([options, 'optionalAccess', _208 => _208.maxStaleTimeMs]), () => ( Number.POSITIVE_INFINITY));
8679
8789
  const context = {
8680
- inForeground: _optionalChain([doc, 'optionalAccess', _207 => _207.visibilityState]) !== "hidden",
8790
+ inForeground: _optionalChain([doc, 'optionalAccess', _209 => _209.visibilityState]) !== "hidden",
8681
8791
  lastSuccessfulPollAt: startTime,
8682
8792
  count: 0,
8683
8793
  backoff: 0
@@ -8755,10 +8865,10 @@ function makePoller(callback, intervalMs, options) {
8755
8865
  pollNowIfStale();
8756
8866
  }
8757
8867
  function onVisibilityChange() {
8758
- setInForeground(_optionalChain([doc, 'optionalAccess', _208 => _208.visibilityState]) !== "hidden");
8868
+ setInForeground(_optionalChain([doc, 'optionalAccess', _210 => _210.visibilityState]) !== "hidden");
8759
8869
  }
8760
- _optionalChain([doc, 'optionalAccess', _209 => _209.addEventListener, 'call', _210 => _210("visibilitychange", onVisibilityChange)]);
8761
- _optionalChain([win, 'optionalAccess', _211 => _211.addEventListener, 'call', _212 => _212("online", onVisibilityChange)]);
8870
+ _optionalChain([doc, 'optionalAccess', _211 => _211.addEventListener, 'call', _212 => _212("visibilitychange", onVisibilityChange)]);
8871
+ _optionalChain([win, 'optionalAccess', _213 => _213.addEventListener, 'call', _214 => _214("online", onVisibilityChange)]);
8762
8872
  fsm.start();
8763
8873
  return {
8764
8874
  inc,
@@ -8976,5 +9086,6 @@ var NotificationsApiError = HttpError;
8976
9086
 
8977
9087
 
8978
9088
 
8979
- exports.ClientMsgCode = ClientMsgCode; exports.CommentsApiError = CommentsApiError; exports.CrdtType = CrdtType; exports.DefaultMap = DefaultMap; exports.DerivedSignal = DerivedSignal; exports.HttpError = HttpError; exports.LiveList = LiveList; exports.LiveMap = LiveMap; exports.LiveObject = LiveObject; exports.MutableSignal = MutableSignal; exports.NotificationsApiError = NotificationsApiError; exports.OpCode = OpCode; exports.Permission = Permission; exports.Promise_withResolvers = Promise_withResolvers; exports.ServerMsgCode = ServerMsgCode; exports.Signal = Signal; exports.SortedList = SortedList; exports.TextEditorType = TextEditorType; exports.WebsocketCloseCodes = WebsocketCloseCodes; exports.ackOp = ackOp; exports.asPos = asPos; exports.assert = assert; exports.assertNever = assertNever; exports.autoRetry = autoRetry; exports.b64decode = b64decode; exports.batch = batch; exports.chunk = chunk; exports.cloneLson = cloneLson; exports.compactObject = compactObject; exports.console = fancy_console_exports; exports.convertToCommentData = convertToCommentData; exports.convertToCommentUserReaction = convertToCommentUserReaction; exports.convertToInboxNotificationData = convertToInboxNotificationData; exports.convertToThreadData = convertToThreadData; exports.createClient = createClient; exports.createCommentAttachmentId = createCommentAttachmentId; exports.createCommentId = createCommentId; exports.createInboxNotificationId = createInboxNotificationId; exports.createThreadId = createThreadId; exports.deprecate = deprecate; exports.deprecateIf = deprecateIf; exports.detectDupes = detectDupes; exports.errorIf = errorIf; exports.freeze = freeze; exports.generateCommentUrl = generateCommentUrl; exports.getMentionedIdsFromCommentBody = getMentionedIdsFromCommentBody; exports.html = html; exports.htmlSafe = htmlSafe; exports.isChildCrdt = isChildCrdt; exports.isCommentBodyLink = isCommentBodyLink; exports.isCommentBodyMention = isCommentBodyMention; exports.isCommentBodyText = isCommentBodyText; exports.isJsonArray = isJsonArray; exports.isJsonObject = isJsonObject; exports.isJsonScalar = isJsonScalar; exports.isLiveNode = isLiveNode; exports.isPlainObject = isPlainObject; exports.isRootCrdt = isRootCrdt; exports.kInternal = kInternal; exports.legacy_patchImmutableObject = legacy_patchImmutableObject; exports.lsonToJson = lsonToJson; exports.makeEventSource = makeEventSource; exports.makePoller = makePoller; exports.makePosition = makePosition; exports.mapValues = mapValues; exports.memoizeOnSuccess = memoizeOnSuccess; exports.nanoid = nanoid; exports.nn = nn; exports.objectToQuery = objectToQuery; exports.patchLiveObjectKey = patchLiveObjectKey; exports.raise = raise; exports.resolveUsersInCommentBody = resolveUsersInCommentBody; exports.shallow = shallow; exports.stringify = stringify; exports.stringifyCommentBody = stringifyCommentBody; exports.throwUsageError = throwUsageError; exports.toAbsoluteUrl = toAbsoluteUrl; exports.toPlainLson = toPlainLson; exports.tryParseJson = tryParseJson; exports.unstringify = unstringify; exports.url = url; exports.urljoin = urljoin; exports.wait = wait; exports.withTimeout = withTimeout;
9089
+
9090
+ exports.ClientMsgCode = ClientMsgCode; exports.CommentsApiError = CommentsApiError; exports.CrdtType = CrdtType; exports.DefaultMap = DefaultMap; exports.DerivedSignal = DerivedSignal; exports.HttpError = HttpError; exports.LiveList = LiveList; exports.LiveMap = LiveMap; exports.LiveObject = LiveObject; exports.LiveblocksError = LiveblocksError; exports.MutableSignal = MutableSignal; exports.NotificationsApiError = NotificationsApiError; exports.OpCode = OpCode; exports.Permission = Permission; exports.Promise_withResolvers = Promise_withResolvers; exports.ServerMsgCode = ServerMsgCode; exports.Signal = Signal; exports.SortedList = SortedList; exports.TextEditorType = TextEditorType; exports.WebsocketCloseCodes = WebsocketCloseCodes; exports.ackOp = ackOp; exports.asPos = asPos; exports.assert = assert; exports.assertNever = assertNever; exports.autoRetry = autoRetry; exports.b64decode = b64decode; exports.batch = batch; exports.chunk = chunk; exports.cloneLson = cloneLson; exports.compactObject = compactObject; exports.console = fancy_console_exports; exports.convertToCommentData = convertToCommentData; exports.convertToCommentUserReaction = convertToCommentUserReaction; exports.convertToInboxNotificationData = convertToInboxNotificationData; exports.convertToThreadData = convertToThreadData; exports.createClient = createClient; exports.createCommentAttachmentId = createCommentAttachmentId; exports.createCommentId = createCommentId; exports.createInboxNotificationId = createInboxNotificationId; exports.createThreadId = createThreadId; exports.deprecate = deprecate; exports.deprecateIf = deprecateIf; exports.detectDupes = detectDupes; exports.errorIf = errorIf; exports.freeze = freeze; exports.generateCommentUrl = generateCommentUrl; exports.getMentionedIdsFromCommentBody = getMentionedIdsFromCommentBody; exports.html = html; exports.htmlSafe = htmlSafe; exports.isChildCrdt = isChildCrdt; exports.isCommentBodyLink = isCommentBodyLink; exports.isCommentBodyMention = isCommentBodyMention; exports.isCommentBodyText = isCommentBodyText; exports.isJsonArray = isJsonArray; exports.isJsonObject = isJsonObject; exports.isJsonScalar = isJsonScalar; exports.isLiveNode = isLiveNode; exports.isPlainObject = isPlainObject; exports.isRootCrdt = isRootCrdt; exports.isStartsWithOperator = isStartsWithOperator; exports.kInternal = kInternal; exports.legacy_patchImmutableObject = legacy_patchImmutableObject; exports.lsonToJson = lsonToJson; exports.makeEventSource = makeEventSource; exports.makePoller = makePoller; exports.makePosition = makePosition; exports.mapValues = mapValues; exports.memoizeOnSuccess = memoizeOnSuccess; exports.nanoid = nanoid; exports.nn = nn; exports.objectToQuery = objectToQuery; exports.patchLiveObjectKey = patchLiveObjectKey; exports.raise = raise; exports.resolveUsersInCommentBody = resolveUsersInCommentBody; exports.shallow = shallow; exports.stringify = stringify; exports.stringifyCommentBody = stringifyCommentBody; exports.throwUsageError = throwUsageError; exports.toAbsoluteUrl = toAbsoluteUrl; exports.toPlainLson = toPlainLson; exports.tryParseJson = tryParseJson; exports.url = url; exports.urljoin = urljoin; exports.wait = wait; exports.withTimeout = withTimeout;
8980
9091
  //# sourceMappingURL=index.js.map