@liveblocks/core 2.16.0-toolbars5 → 2.16.0

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 = "2.16.0-toolbars5";
9
+ var PKG_VERSION = "2.16.0";
10
10
  var PKG_FORMAT = "esm";
11
11
 
12
12
  // src/dupe-detection.ts
@@ -166,6 +166,14 @@ 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);
@@ -251,13 +259,48 @@ function memoizeOnSuccess(factoryFn) {
251
259
  }
252
260
 
253
261
  // src/lib/autoRetry.ts
254
- var HttpError = class extends Error {
255
- constructor(message, status, details) {
262
+ var HttpError = class _HttpError extends Error {
263
+ response;
264
+ details;
265
+ constructor(message, response, details) {
256
266
  super(message);
257
- this.message = message;
258
- this.status = status;
267
+ this.name = "HttpError";
268
+ this.response = response;
259
269
  this.details = details;
260
270
  }
271
+ static async fromResponse(response) {
272
+ let bodyAsText;
273
+ try {
274
+ bodyAsText = await response.text();
275
+ } catch {
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 bodyAsJsonObject?.message === "string" ? bodyAsJsonObject.message : "";
284
+ message ||= typeof bodyAsJsonObject?.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 {
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
+ }
261
304
  };
262
305
  var DONT_RETRY_4XX = (x) => x instanceof HttpError && x.status >= 400 && x.status < 500;
263
306
  async function autoRetry(promiseFn, maxTries, backoff, shouldStopRetrying = DONT_RETRY_4XX) {
@@ -323,7 +366,12 @@ function makeEventSource() {
323
366
  }).finally(() => unsub?.());
324
367
  }
325
368
  function notify(event) {
326
- _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;
327
375
  }
328
376
  function count() {
329
377
  return _observers.size;
@@ -364,8 +412,9 @@ function makeBufferableEventSource() {
364
412
  function notifyOrBuffer(event) {
365
413
  if (_buffer !== null) {
366
414
  _buffer.push(event);
415
+ return false;
367
416
  } else {
368
- eventSource2.notify(event);
417
+ return eventSource2.notify(event);
369
418
  }
370
419
  }
371
420
  return {
@@ -670,32 +719,15 @@ var MutableSignal = class extends AbstractSignal {
670
719
  };
671
720
 
672
721
  // src/lib/stringify.ts
673
- var EXPLICIT_UNDEFINED_PLACEHOLDER = "_explicit_undefined";
674
722
  function replacer(_key, value) {
675
723
  return value !== null && typeof value === "object" && !Array.isArray(value) ? Object.keys(value).sort().reduce((sorted, key) => {
676
724
  sorted[key] = value[key];
677
725
  return sorted;
678
- }, {}) : value === void 0 ? EXPLICIT_UNDEFINED_PLACEHOLDER : value;
679
- }
680
- function reviver(key, value) {
681
- if (!key && value === EXPLICIT_UNDEFINED_PLACEHOLDER) {
682
- return void 0;
683
- }
684
- if (value && typeof value === "object") {
685
- for (const k in value) {
686
- if (value[k] === EXPLICIT_UNDEFINED_PLACEHOLDER) {
687
- Object.defineProperty(value, k, { value: void 0 });
688
- }
689
- }
690
- }
691
- return value;
726
+ }, {}) : value;
692
727
  }
693
728
  function stringify(value) {
694
729
  return JSON.stringify(value, replacer);
695
730
  }
696
- function unstringify(value) {
697
- return JSON.parse(value, reviver);
698
- }
699
731
 
700
732
  // src/lib/batch.ts
701
733
  var DEFAULT_SIZE = 50;
@@ -911,14 +943,6 @@ var DefaultMap = class extends Map {
911
943
  }
912
944
  };
913
945
 
914
- // src/lib/guards.ts
915
- function isPlainObject(blob) {
916
- return blob !== null && typeof blob === "object" && Object.prototype.toString.call(blob) === "[object Object]";
917
- }
918
- function isStartsWithOperator(blob) {
919
- return isPlainObject(blob) && typeof blob.startsWith === "string";
920
- }
921
-
922
946
  // src/lib/objectToQuery.ts
923
947
  var identifierRegex = /^[a-zA-Z_][a-zA-Z0-9_]*$/;
924
948
  function objectToQuery(obj) {
@@ -968,9 +992,7 @@ function objectToQuery(obj) {
968
992
  ...getFiltersFromKeyValuePairsWithOperator(nKeyValuePairsWithOperator)
969
993
  ];
970
994
  });
971
- return filterList.map(
972
- ({ key, operator, value }) => formatFilter(key, operator, formatFilterValue(value))
973
- ).join(" AND ");
995
+ return filterList.map(({ key, operator, value }) => `${key}${operator}${quote(value)}`).join(" ");
974
996
  }
975
997
  var getFiltersFromKeyValuePairs = (keyValuePairs) => {
976
998
  const filters = [];
@@ -997,29 +1019,27 @@ var getFiltersFromKeyValuePairsWithOperator = (keyValuePairsWithOperator) => {
997
1019
  return filters;
998
1020
  };
999
1021
  var isSimpleValue = (value) => {
1000
- return typeof value === "string" || typeof value === "number" || typeof value === "boolean";
1001
- };
1002
- var formatFilter = (key, operator, value) => {
1003
- return `${key}${operator}${value}`;
1022
+ return typeof value === "string" || typeof value === "number" || typeof value === "boolean" || value === null;
1004
1023
  };
1005
1024
  var formatFilterKey = (key, nestedKey) => {
1006
1025
  if (nestedKey) {
1007
- return `${key}[${JSON.stringify(nestedKey)}]`;
1026
+ return `${key}[${quote(nestedKey)}]`;
1008
1027
  }
1009
1028
  return key;
1010
1029
  };
1011
- var formatFilterValue = (value) => {
1012
- if (typeof value === "string") {
1013
- if (isStringEmpty(value)) {
1014
- throw new Error("Value cannot be empty");
1015
- }
1016
- return JSON.stringify(value);
1017
- }
1018
- return value.toString();
1019
- };
1020
1030
  var isStringEmpty = (value) => {
1021
1031
  return !value || value.toString().trim() === "";
1022
1032
  };
1033
+ function quote(input) {
1034
+ const result = JSON.stringify(input);
1035
+ if (typeof input !== "string") {
1036
+ return result;
1037
+ }
1038
+ if (result.includes("'")) {
1039
+ return result;
1040
+ }
1041
+ return `'${result.slice(1, -1).replace(/\\"/g, '"')}'`;
1042
+ }
1023
1043
 
1024
1044
  // src/lib/url.ts
1025
1045
  function toURLSearchParams(params) {
@@ -1844,14 +1864,7 @@ var HttpClient = class {
1844
1864
  async #fetch(endpoint, authValue, options, params) {
1845
1865
  const response = await this.#rawFetch(endpoint, authValue, options, params);
1846
1866
  if (!response.ok) {
1847
- let error3;
1848
- try {
1849
- const errorBody = await response.json();
1850
- error3 = new HttpError(errorBody.message, response.status, errorBody);
1851
- } catch {
1852
- error3 = new HttpError(response.statusText, response.status);
1853
- }
1854
- throw error3;
1867
+ throw await HttpError.fromResponse(response);
1855
1868
  }
1856
1869
  let body;
1857
1870
  try {
@@ -2495,13 +2508,6 @@ var StopRetrying = class extends Error {
2495
2508
  super(reason);
2496
2509
  }
2497
2510
  };
2498
- var LiveblocksError = class extends Error {
2499
- /** @internal */
2500
- constructor(message, code) {
2501
- super(message);
2502
- this.code = code;
2503
- }
2504
- };
2505
2511
  function nextBackoffDelay(currentDelay, delays) {
2506
2512
  return delays.find((delay) => delay > currentDelay) ?? delays[delays.length - 1];
2507
2513
  }
@@ -2611,11 +2617,10 @@ var assign = (patch) => (ctx) => ctx.patch(patch);
2611
2617
  function createConnectionStateMachine(delegates, options) {
2612
2618
  const onMessage = makeBufferableEventSource();
2613
2619
  onMessage.pause();
2614
- const onLiveblocksError = makeEventSource();
2615
- function fireErrorEvent(errmsg, errcode) {
2620
+ const onConnectionError = makeEventSource();
2621
+ function fireErrorEvent(message, code) {
2616
2622
  return () => {
2617
- const err = new LiveblocksError(errmsg, errcode);
2618
- onLiveblocksError.notify(err);
2623
+ onConnectionError.notify({ message, code });
2619
2624
  };
2620
2625
  }
2621
2626
  const initialContext = {
@@ -2973,7 +2978,7 @@ function createConnectionStateMachine(delegates, options) {
2973
2978
  didConnect,
2974
2979
  didDisconnect,
2975
2980
  onMessage: onMessage.observable,
2976
- onLiveblocksError: onLiveblocksError.observable
2981
+ onConnectionError: onConnectionError.observable
2977
2982
  }
2978
2983
  };
2979
2984
  }
@@ -6237,6 +6242,83 @@ var ManagedOthers = class {
6237
6242
  }
6238
6243
  };
6239
6244
 
6245
+ // src/types/LiveblocksError.ts
6246
+ var LiveblocksError = class _LiveblocksError extends Error {
6247
+ context;
6248
+ constructor(message, context, cause) {
6249
+ super(message, { cause });
6250
+ this.context = context;
6251
+ this.name = "LiveblocksError";
6252
+ }
6253
+ /** Convenience accessor for error.context.roomId (if available) */
6254
+ get roomId() {
6255
+ return this.context.roomId;
6256
+ }
6257
+ /** @deprecated Prefer using `context.code` instead, to enable type narrowing */
6258
+ get code() {
6259
+ return this.context.code;
6260
+ }
6261
+ /**
6262
+ * Creates a LiveblocksError from a generic error, by attaching Liveblocks
6263
+ * contextual information like room ID, thread ID, etc.
6264
+ */
6265
+ static from(context, cause) {
6266
+ return new _LiveblocksError(
6267
+ defaultMessageFromContext(context),
6268
+ context,
6269
+ cause
6270
+ );
6271
+ }
6272
+ };
6273
+ function defaultMessageFromContext(context) {
6274
+ switch (context.type) {
6275
+ case "ROOM_CONNECTION_ERROR": {
6276
+ switch (context.code) {
6277
+ case 4001:
6278
+ return "Not allowed to connect to the room";
6279
+ case 4005:
6280
+ return "Room is already full";
6281
+ case 4006:
6282
+ return "Kicked out of the room, because the room ID changed";
6283
+ default:
6284
+ return "Could not connect to the room";
6285
+ }
6286
+ }
6287
+ case "CREATE_THREAD_ERROR":
6288
+ return "Could not create new thread";
6289
+ case "DELETE_THREAD_ERROR":
6290
+ return "Could not delete thread";
6291
+ case "EDIT_THREAD_METADATA_ERROR":
6292
+ return "Could not edit thread metadata";
6293
+ case "MARK_THREAD_AS_RESOLVED_ERROR":
6294
+ return "Could not mark thread as resolved";
6295
+ case "MARK_THREAD_AS_UNRESOLVED_ERROR":
6296
+ return "Could not mark thread as unresolved";
6297
+ case "CREATE_COMMENT_ERROR":
6298
+ return "Could not create new comment";
6299
+ case "EDIT_COMMENT_ERROR":
6300
+ return "Could not edit comment";
6301
+ case "DELETE_COMMENT_ERROR":
6302
+ return "Could not delete comment";
6303
+ case "ADD_REACTION_ERROR":
6304
+ return "Could not add reaction";
6305
+ case "REMOVE_REACTION_ERROR":
6306
+ return "Could not remove reaction";
6307
+ case "MARK_INBOX_NOTIFICATION_AS_READ_ERROR":
6308
+ return "Could not mark inbox notification as read";
6309
+ case "DELETE_INBOX_NOTIFICATION_ERROR":
6310
+ return "Could not delete inbox notification";
6311
+ case "MARK_ALL_INBOX_NOTIFICATIONS_AS_READ_ERROR":
6312
+ return "Could not mark all inbox notifications as read";
6313
+ case "DELETE_ALL_INBOX_NOTIFICATIONS_ERROR":
6314
+ return "Could not delete all inbox notifications";
6315
+ case "UPDATE_NOTIFICATION_SETTINGS_ERROR":
6316
+ return "Could not update notification settings";
6317
+ default:
6318
+ return assertNever(context, "Unhandled case");
6319
+ }
6320
+ }
6321
+
6240
6322
  // src/room.ts
6241
6323
  var MAX_SOCKET_MESSAGE_SIZE = 1024 * 1024 - 1024;
6242
6324
  function makeIdFactory(connectionId) {
@@ -6401,13 +6483,17 @@ function createRoom(options, config) {
6401
6483
  managedSocket.events.statusDidChange.subscribe(handleConnectionLossEvent);
6402
6484
  managedSocket.events.didConnect.subscribe(onDidConnect);
6403
6485
  managedSocket.events.didDisconnect.subscribe(onDidDisconnect);
6404
- managedSocket.events.onLiveblocksError.subscribe((err) => {
6405
- if (process.env.NODE_ENV !== "production") {
6406
- error2(
6407
- `Connection to websocket server closed. Reason: ${err.message} (code: ${err.code}).`
6408
- );
6486
+ managedSocket.events.onConnectionError.subscribe(({ message, code }) => {
6487
+ const type = "ROOM_CONNECTION_ERROR";
6488
+ const err = new LiveblocksError(message, { type, code, roomId });
6489
+ const didNotify = config.errorEventSource.notify(err);
6490
+ if (!didNotify) {
6491
+ if (process.env.NODE_ENV !== "production") {
6492
+ error2(
6493
+ `Connection to websocket server closed. Reason: ${message} (code: ${code}).`
6494
+ );
6495
+ }
6409
6496
  }
6410
- eventHub.error.notify(err);
6411
6497
  });
6412
6498
  const pool = {
6413
6499
  roomId: config.roomId,
@@ -6470,7 +6556,6 @@ function createRoom(options, config) {
6470
6556
  self: makeEventSource(),
6471
6557
  myPresence: makeEventSource(),
6472
6558
  others: makeEventSource(),
6473
- error: makeEventSource(),
6474
6559
  storageBatch: makeEventSource(),
6475
6560
  history: makeEventSource(),
6476
6561
  storageDidLoad: makeEventSource(),
@@ -7071,11 +7156,12 @@ ${Array.from(traces).join("\n\n")}`
7071
7156
  }
7072
7157
  return messages;
7073
7158
  }
7074
- function updateYDoc(update, guid) {
7159
+ function updateYDoc(update, guid, isV2) {
7075
7160
  const clientMsg = {
7076
7161
  type: 301 /* UPDATE_YDOC */,
7077
7162
  update,
7078
- guid
7163
+ guid,
7164
+ v2: isV2
7079
7165
  };
7080
7166
  context.buffer.messages.push(clientMsg);
7081
7167
  eventHub.ydoc.notify(clientMsg);
@@ -7156,14 +7242,15 @@ ${Array.from(traces).join("\n\n")}`
7156
7242
  root: nn(context.root)
7157
7243
  };
7158
7244
  }
7159
- function fetchYDoc(vector, guid) {
7245
+ function fetchYDoc(vector, guid, isV2) {
7160
7246
  if (!context.buffer.messages.find((m) => {
7161
- return m.type === 300 /* FETCH_YDOC */ && m.vector === vector && m.guid === guid;
7247
+ return m.type === 300 /* FETCH_YDOC */ && m.vector === vector && m.guid === guid && m.v2 === isV2;
7162
7248
  })) {
7163
7249
  context.buffer.messages.push({
7164
7250
  type: 300 /* FETCH_YDOC */,
7165
7251
  vector,
7166
- guid
7252
+ guid,
7253
+ v2: isV2
7167
7254
  });
7168
7255
  }
7169
7256
  flushNowOrSoon();
@@ -7308,7 +7395,6 @@ ${Array.from(traces).join("\n\n")}`
7308
7395
  others: eventHub.others.observable,
7309
7396
  self: eventHub.self.observable,
7310
7397
  myPresence: eventHub.myPresence.observable,
7311
- error: eventHub.error.observable,
7312
7398
  /** @deprecated */
7313
7399
  storage: eventHub.storageBatch.observable,
7314
7400
  storageBatch: eventHub.storageBatch.observable,
@@ -7499,7 +7585,11 @@ ${Array.from(traces).join("\n\n")}`
7499
7585
  attachmentUrlsStore: httpClient.getOrCreateAttachmentUrlsStore(roomId)
7500
7586
  },
7501
7587
  id: config.roomId,
7502
- subscribe: makeClassicSubscribeFn(events),
7588
+ subscribe: makeClassicSubscribeFn(
7589
+ config.roomId,
7590
+ events,
7591
+ config.errorEventSource
7592
+ ),
7503
7593
  connect: () => managedSocket.connect(),
7504
7594
  reconnect: () => managedSocket.reconnect(),
7505
7595
  disconnect: () => managedSocket.disconnect(),
@@ -7568,7 +7658,7 @@ ${Array.from(traces).join("\n\n")}`
7568
7658
  { enumerable: false }
7569
7659
  );
7570
7660
  }
7571
- function makeClassicSubscribeFn(events) {
7661
+ function makeClassicSubscribeFn(roomId, events, errorEvents) {
7572
7662
  function subscribeToLiveStructureDeeply(node, callback) {
7573
7663
  return events.storageBatch.subscribe((updates) => {
7574
7664
  const relatedUpdates = updates.filter(
@@ -7608,8 +7698,13 @@ function makeClassicSubscribeFn(events) {
7608
7698
  return cb(others, internalEvent);
7609
7699
  });
7610
7700
  }
7611
- case "error":
7612
- return events.error.subscribe(callback);
7701
+ case "error": {
7702
+ return errorEvents.subscribe((err) => {
7703
+ if (err.roomId === roomId) {
7704
+ return callback(err);
7705
+ }
7706
+ });
7707
+ }
7613
7708
  case "status":
7614
7709
  return events.status.subscribe(callback);
7615
7710
  case "lost-connection":
@@ -7781,6 +7876,7 @@ function createClient(options) {
7781
7876
  },
7782
7877
  enableDebugLogging: clientOptions.enableDebugLogging,
7783
7878
  baseUrl,
7879
+ errorEventSource: liveblocksErrorSource,
7784
7880
  unstable_fallbackToHTTP: !!clientOptions.unstable_fallbackToHTTP,
7785
7881
  unstable_streamData: !!clientOptions.unstable_streamData,
7786
7882
  roomHttpClient: httpClient,
@@ -7863,6 +7959,7 @@ function createClient(options) {
7863
7959
  }
7864
7960
  const syncStatusSources = [];
7865
7961
  const syncStatusSignal = new Signal("synchronized");
7962
+ const liveblocksErrorSource = makeEventSource();
7866
7963
  function getSyncStatus() {
7867
7964
  const status = syncStatusSignal.get();
7868
7965
  return status === "synchronizing" ? status : "synchronized";
@@ -7922,6 +8019,7 @@ function createClient(options) {
7922
8019
  },
7923
8020
  getSyncStatus,
7924
8021
  events: {
8022
+ error: liveblocksErrorSource,
7925
8023
  syncStatus: syncStatusSignal
7926
8024
  },
7927
8025
  // Internal
@@ -7937,7 +8035,14 @@ function createClient(options) {
7937
8035
  httpClient,
7938
8036
  // Type-level helper only, it's effectively only an identity-function at runtime
7939
8037
  as: () => client,
7940
- createSyncSource
8038
+ createSyncSource,
8039
+ emitError: (context, cause) => {
8040
+ const error3 = LiveblocksError.from(context, cause);
8041
+ const didNotify = liveblocksErrorSource.notify(error3);
8042
+ if (!didNotify) {
8043
+ error2(error3.message);
8044
+ }
8045
+ }
7941
8046
  }
7942
8047
  },
7943
8048
  kInternal,
@@ -8773,6 +8878,7 @@ function makePoller(callback, intervalMs, options) {
8773
8878
  }
8774
8879
  doc?.addEventListener("visibilitychange", onVisibilityChange);
8775
8880
  win?.addEventListener("online", onVisibilityChange);
8881
+ win?.addEventListener("focus", pollNowIfStale);
8776
8882
  fsm.start();
8777
8883
  return {
8778
8884
  inc,
@@ -8915,6 +9021,7 @@ export {
8915
9021
  LiveList,
8916
9022
  LiveMap,
8917
9023
  LiveObject,
9024
+ LiveblocksError,
8918
9025
  MutableSignal,
8919
9026
  NotificationsApiError,
8920
9027
  OpCode,
@@ -8986,7 +9093,6 @@ export {
8986
9093
  toAbsoluteUrl,
8987
9094
  toPlainLson,
8988
9095
  tryParseJson,
8989
- unstringify,
8990
9096
  url,
8991
9097
  urljoin,
8992
9098
  wait,