@liveblocks/core 1.2.4 → 1.3.1

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
@@ -1,6 +1,12 @@
1
+ var __defProp = Object.defineProperty;
2
+ var __export = (target, all) => {
3
+ for (var name in all)
4
+ __defProp(target, name, { get: all[name], enumerable: true });
5
+ };
6
+
1
7
  // src/version.ts
2
8
  var PKG_NAME = "@liveblocks/core";
3
- var PKG_VERSION = "1.2.4";
9
+ var PKG_VERSION = "1.3.1";
4
10
  var PKG_FORMAT = "esm";
5
11
 
6
12
  // src/dupe-detection.ts
@@ -150,6 +156,13 @@ function makeEventSource() {
150
156
  }
151
157
 
152
158
  // src/lib/fancy-console.ts
159
+ var fancy_console_exports = {};
160
+ __export(fancy_console_exports, {
161
+ error: () => error2,
162
+ errorWithTitle: () => errorWithTitle,
163
+ warn: () => warn,
164
+ warnWithTitle: () => warnWithTitle
165
+ });
153
166
  var badge = "background:#0e0d12;border-radius:9999px;color:#fff;padding:3px 7px;font-family:sans-serif;font-weight:600;";
154
167
  var bold = "font-weight:600";
155
168
  function wrap(method) {
@@ -624,6 +637,11 @@ var ServerMsgCode = /* @__PURE__ */ ((ServerMsgCode2) => {
624
637
  ServerMsgCode2[ServerMsgCode2["UPDATE_STORAGE"] = 201] = "UPDATE_STORAGE";
625
638
  ServerMsgCode2[ServerMsgCode2["REJECT_STORAGE_OP"] = 299] = "REJECT_STORAGE_OP";
626
639
  ServerMsgCode2[ServerMsgCode2["UPDATE_YDOC"] = 300] = "UPDATE_YDOC";
640
+ ServerMsgCode2[ServerMsgCode2["THREAD_CREATED"] = 400] = "THREAD_CREATED";
641
+ ServerMsgCode2[ServerMsgCode2["THREAD_METADATA_UPDATED"] = 401] = "THREAD_METADATA_UPDATED";
642
+ ServerMsgCode2[ServerMsgCode2["COMMENT_CREATED"] = 402] = "COMMENT_CREATED";
643
+ ServerMsgCode2[ServerMsgCode2["COMMENT_EDITED"] = 403] = "COMMENT_EDITED";
644
+ ServerMsgCode2[ServerMsgCode2["COMMENT_DELETED"] = 404] = "COMMENT_DELETED";
627
645
  return ServerMsgCode2;
628
646
  })(ServerMsgCode || {});
629
647
 
@@ -1152,10 +1170,10 @@ function createConnectionStateMachine(delegates, options) {
1152
1170
  };
1153
1171
  }
1154
1172
  var ManagedSocket = class {
1155
- constructor(delegates, enableDebugLogging = false) {
1173
+ constructor(delegates, enableDebugLogging = false, waitForActorId = true) {
1156
1174
  const { machine, events, cleanups } = createConnectionStateMachine(
1157
1175
  delegates,
1158
- { waitForActorId: true, enableDebugLogging }
1176
+ { waitForActorId, enableDebugLogging }
1159
1177
  );
1160
1178
  this.machine = machine;
1161
1179
  this.events = events;
@@ -1237,6 +1255,9 @@ var ManagedSocket = class {
1237
1255
  function canWriteStorage(scopes) {
1238
1256
  return scopes.includes("room:write" /* Write */);
1239
1257
  }
1258
+ function canComment(scopes) {
1259
+ return scopes.includes("comments:write" /* CommentsWrite */) || scopes.includes("room:write" /* Write */);
1260
+ }
1240
1261
  function isValidAuthTokenPayload(data) {
1241
1262
  return isPlainObject(data) && (data.k === "acc" /* ACCESS_TOKEN */ || data.k === "id" /* ID_TOKEN */ || data.k === "sec-legacy" /* SECRET_LEGACY */);
1242
1263
  }
@@ -1647,6 +1668,149 @@ function errorIf(condition, message) {
1647
1668
  }
1648
1669
  }
1649
1670
 
1671
+ // src/comments/index.ts
1672
+ function getAuthBearerHeaderFromAuthValue(authValue) {
1673
+ if (authValue.type === "public") {
1674
+ return authValue.publicApiKey;
1675
+ } else {
1676
+ return authValue.token.raw;
1677
+ }
1678
+ }
1679
+ function createCommentsApi(roomId, getAuthValue, { serverEndpoint }) {
1680
+ async function fetchJson(endpoint, options) {
1681
+ const response = await fetchApi(roomId, endpoint, options);
1682
+ if (!response.ok) {
1683
+ if (response.status >= 400 && response.status < 600) {
1684
+ let errorMessage = "";
1685
+ try {
1686
+ const errorBody = await response.json();
1687
+ errorMessage = errorBody.message;
1688
+ } catch (error3) {
1689
+ errorMessage = response.statusText;
1690
+ }
1691
+ throw new Error(
1692
+ `Request failed with status ${response.status}: ${errorMessage}`
1693
+ );
1694
+ }
1695
+ }
1696
+ let body;
1697
+ try {
1698
+ body = await response.json();
1699
+ } catch {
1700
+ body = {};
1701
+ }
1702
+ return body;
1703
+ }
1704
+ async function fetchApi(roomId2, endpoint, options) {
1705
+ const authValue = await getAuthValue();
1706
+ const url = `${serverEndpoint}/c/rooms/${roomId2}${endpoint}`;
1707
+ return await fetch(url, {
1708
+ ...options,
1709
+ headers: {
1710
+ ...options?.headers,
1711
+ Authorization: `Bearer ${getAuthBearerHeaderFromAuthValue(authValue)}`
1712
+ }
1713
+ });
1714
+ }
1715
+ async function getThreads() {
1716
+ const response = await fetchApi(roomId, "/threads");
1717
+ if (response.ok) {
1718
+ const json = await response.json();
1719
+ return json.data;
1720
+ } else if (response.status === 404) {
1721
+ return [];
1722
+ } else {
1723
+ throw new Error("There was an error while getting threads.");
1724
+ }
1725
+ }
1726
+ function createThread({
1727
+ metadata,
1728
+ body,
1729
+ commentId,
1730
+ threadId
1731
+ }) {
1732
+ return fetchJson("/threads", {
1733
+ method: "POST",
1734
+ headers: {
1735
+ "Content-Type": "application/json"
1736
+ },
1737
+ body: JSON.stringify({
1738
+ id: threadId,
1739
+ comment: {
1740
+ id: commentId,
1741
+ body
1742
+ },
1743
+ metadata
1744
+ })
1745
+ });
1746
+ }
1747
+ function editThreadMetadata({
1748
+ metadata,
1749
+ threadId
1750
+ }) {
1751
+ return fetchJson(
1752
+ `/threads/${threadId}/metadata`,
1753
+ {
1754
+ method: "POST",
1755
+ headers: {
1756
+ "Content-Type": "application/json"
1757
+ },
1758
+ body: JSON.stringify(metadata)
1759
+ }
1760
+ );
1761
+ }
1762
+ function createComment({
1763
+ threadId,
1764
+ commentId,
1765
+ body
1766
+ }) {
1767
+ return fetchJson(`/threads/${threadId}/comments`, {
1768
+ method: "POST",
1769
+ headers: {
1770
+ "Content-Type": "application/json"
1771
+ },
1772
+ body: JSON.stringify({
1773
+ id: commentId,
1774
+ body
1775
+ })
1776
+ });
1777
+ }
1778
+ function editComment({
1779
+ threadId,
1780
+ commentId,
1781
+ body
1782
+ }) {
1783
+ return fetchJson(
1784
+ `/threads/${threadId}/comments/${commentId}`,
1785
+ {
1786
+ method: "POST",
1787
+ headers: {
1788
+ "Content-Type": "application/json"
1789
+ },
1790
+ body: JSON.stringify({
1791
+ body
1792
+ })
1793
+ }
1794
+ );
1795
+ }
1796
+ async function deleteComment({
1797
+ threadId,
1798
+ commentId
1799
+ }) {
1800
+ await fetchJson(`/threads/${threadId}/comments/${commentId}`, {
1801
+ method: "DELETE"
1802
+ });
1803
+ }
1804
+ return {
1805
+ getThreads,
1806
+ createThread,
1807
+ editThreadMetadata,
1808
+ createComment,
1809
+ editComment,
1810
+ deleteComment
1811
+ };
1812
+ }
1813
+
1650
1814
  // src/lib/position.ts
1651
1815
  var MIN_CODE = 32;
1652
1816
  var MAX_CODE = 126;
@@ -4190,19 +4354,6 @@ var ClientMsgCode = /* @__PURE__ */ ((ClientMsgCode2) => {
4190
4354
  return ClientMsgCode2;
4191
4355
  })(ClientMsgCode || {});
4192
4356
 
4193
- // src/lib/LegacyArray.ts
4194
- function asArrayWithLegacyMethods(arr) {
4195
- Object.defineProperty(arr, "count", {
4196
- value: arr.length,
4197
- enumerable: false
4198
- });
4199
- Object.defineProperty(arr, "toArray", {
4200
- value: () => arr,
4201
- enumerable: false
4202
- });
4203
- return freeze(arr);
4204
- }
4205
-
4206
4357
  // src/refs/ImmutableRef.ts
4207
4358
  function merge(target, patch) {
4208
4359
  let updated = false;
@@ -4249,6 +4400,7 @@ function makeUser(conn, presence) {
4249
4400
  id,
4250
4401
  info,
4251
4402
  canWrite,
4403
+ canComment: canComment(conn.scopes),
4252
4404
  isReadOnly: !canWrite,
4253
4405
  // Deprecated, kept for backward-compatibility
4254
4406
  presence
@@ -4275,7 +4427,7 @@ var OthersRef = class extends ImmutableRef {
4275
4427
  (connectionId) => this.getUser(Number(connectionId))
4276
4428
  )
4277
4429
  );
4278
- return asArrayWithLegacyMethods(users);
4430
+ return users;
4279
4431
  }
4280
4432
  clearOthers() {
4281
4433
  this._connections = /* @__PURE__ */ new Map();
@@ -4602,7 +4754,7 @@ function createRoom(options, config) {
4602
4754
  } else {
4603
4755
  batchUpdates(() => {
4604
4756
  addToUndoStack(reverse, doNotBatchUpdates);
4605
- context.redoStack = [];
4757
+ context.redoStack.length = 0;
4606
4758
  dispatchOps(ops);
4607
4759
  notify({ storageUpdates }, doNotBatchUpdates);
4608
4760
  });
@@ -4636,7 +4788,8 @@ function createRoom(options, config) {
4636
4788
  history: makeEventSource(),
4637
4789
  storageDidLoad: makeEventSource(),
4638
4790
  storageStatus: makeEventSource(),
4639
- ydoc: makeEventSource()
4791
+ ydoc: makeEventSource(),
4792
+ comments: makeEventSource()
4640
4793
  };
4641
4794
  function sendMessages(messageOrMessages) {
4642
4795
  const message = JSON.stringify(messageOrMessages);
@@ -4677,6 +4830,7 @@ function createRoom(options, config) {
4677
4830
  info: staticSession.userInfo,
4678
4831
  presence: myPresence,
4679
4832
  canWrite,
4833
+ canComment: canComment(dynamicSession.scopes),
4680
4834
  isReadOnly: !canWrite
4681
4835
  // Deprecated, kept for backward-compatibility
4682
4836
  };
@@ -5135,6 +5289,14 @@ ${Array.from(traces).join("\n\n")}`
5135
5289
  }
5136
5290
  break;
5137
5291
  }
5292
+ case 400 /* THREAD_CREATED */:
5293
+ case 401 /* THREAD_METADATA_UPDATED */:
5294
+ case 402 /* COMMENT_CREATED */:
5295
+ case 403 /* COMMENT_EDITED */:
5296
+ case 404 /* COMMENT_DELETED */: {
5297
+ eventHub.comments.notify(message);
5298
+ break;
5299
+ }
5138
5300
  }
5139
5301
  }
5140
5302
  notify(updates, doNotBatchUpdates);
@@ -5322,6 +5484,10 @@ ${Array.from(traces).join("\n\n")}`
5322
5484
  }
5323
5485
  flushNowOrSoon();
5324
5486
  }
5487
+ function clear() {
5488
+ context.undoStack.length = 0;
5489
+ context.redoStack.length = 0;
5490
+ }
5325
5491
  function batch(callback) {
5326
5492
  if (context.activeBatch) {
5327
5493
  return callback();
@@ -5346,7 +5512,7 @@ ${Array.from(traces).join("\n\n")}`
5346
5512
  addToUndoStack(currentBatch.reverseOps, doNotBatchUpdates);
5347
5513
  }
5348
5514
  if (currentBatch.ops.length > 0) {
5349
- context.redoStack = [];
5515
+ context.redoStack.length = 0;
5350
5516
  }
5351
5517
  if (currentBatch.ops.length > 0) {
5352
5518
  dispatchOps(currentBatch.ops);
@@ -5401,8 +5567,12 @@ ${Array.from(traces).join("\n\n")}`
5401
5567
  history: eventHub.history.observable,
5402
5568
  storageDidLoad: eventHub.storageDidLoad.observable,
5403
5569
  storageStatus: eventHub.storageStatus.observable,
5404
- ydoc: eventHub.ydoc.observable
5570
+ ydoc: eventHub.ydoc.observable,
5571
+ comments: eventHub.comments.observable
5405
5572
  };
5573
+ const commentsApi = createCommentsApi(config.roomId, delegates.authenticate, {
5574
+ serverEndpoint: "https://api.liveblocks.io/v2"
5575
+ });
5406
5576
  return Object.defineProperty(
5407
5577
  {
5408
5578
  /* NOTE: Exposing __internal here only to allow testing implementation details in unit tests */
@@ -5446,6 +5616,7 @@ ${Array.from(traces).join("\n\n")}`
5446
5616
  redo,
5447
5617
  canUndo,
5448
5618
  canRedo,
5619
+ clear,
5449
5620
  pause: pauseHistory,
5450
5621
  resume: resumeHistory
5451
5622
  },
@@ -5460,7 +5631,8 @@ ${Array.from(traces).join("\n\n")}`
5460
5631
  getSelf: () => self.current,
5461
5632
  // Presence
5462
5633
  getPresence: () => context.myPresence.current,
5463
- getOthers: () => context.others.current
5634
+ getOthers: () => context.others.current,
5635
+ ...commentsApi
5464
5636
  },
5465
5637
  // Explictly make the __internal field non-enumerable, to avoid aggressive
5466
5638
  // freezing when used with Immer
@@ -6085,6 +6257,222 @@ function shallow(a, b) {
6085
6257
  return shallowObj(a, b);
6086
6258
  }
6087
6259
 
6260
+ // src/lib/AsyncCache.ts
6261
+ var noop = () => {
6262
+ };
6263
+ function isShallowEqual(a, b) {
6264
+ if (a.isLoading !== b.isLoading || a.data === void 0 !== (b.data === void 0) || a.error === void 0 !== (b.error === void 0)) {
6265
+ return false;
6266
+ } else {
6267
+ return shallow(a.data, b.data) && shallow(a.error, b.error);
6268
+ }
6269
+ }
6270
+ function createCacheItem(key, defaultAsyncFunction, options) {
6271
+ let asyncFunction = defaultAsyncFunction;
6272
+ const context = {
6273
+ isInvalid: true
6274
+ };
6275
+ let state = { isLoading: false };
6276
+ let previousState = { isLoading: false };
6277
+ const eventSource2 = makeEventSource();
6278
+ function notify() {
6279
+ const isEqual = options?.isStateEqual ?? isShallowEqual;
6280
+ if (!isEqual(previousState, state)) {
6281
+ previousState = state;
6282
+ eventSource2.notify(state);
6283
+ }
6284
+ }
6285
+ async function resolve() {
6286
+ if (!context.promise) {
6287
+ return;
6288
+ }
6289
+ try {
6290
+ const data = await context.promise;
6291
+ context.isInvalid = false;
6292
+ state = {
6293
+ isLoading: false,
6294
+ data
6295
+ };
6296
+ } catch (error3) {
6297
+ state = {
6298
+ isLoading: false,
6299
+ data: state.data,
6300
+ error: error3
6301
+ };
6302
+ }
6303
+ context.promise = void 0;
6304
+ notify();
6305
+ }
6306
+ async function revalidate() {
6307
+ context.isInvalid = true;
6308
+ return get();
6309
+ }
6310
+ async function get() {
6311
+ if (context.isInvalid) {
6312
+ if (!context.promise) {
6313
+ context.isInvalid = true;
6314
+ context.promise = asyncFunction(key);
6315
+ state = { isLoading: true, data: state.data };
6316
+ notify();
6317
+ }
6318
+ await resolve();
6319
+ }
6320
+ return getState();
6321
+ }
6322
+ function getState() {
6323
+ return state;
6324
+ }
6325
+ function setAsyncFunction(overrideAsyncFunction) {
6326
+ asyncFunction = overrideAsyncFunction;
6327
+ }
6328
+ return {
6329
+ ...eventSource2.observable,
6330
+ setAsyncFunction,
6331
+ get,
6332
+ getState,
6333
+ revalidate
6334
+ };
6335
+ }
6336
+ function createAsyncCache(asyncFunction, options) {
6337
+ const cache = /* @__PURE__ */ new Map();
6338
+ function create(key, overrideAsyncFunction) {
6339
+ let cacheItem = cache.get(key);
6340
+ if (cacheItem) {
6341
+ if (overrideAsyncFunction) {
6342
+ cacheItem.setAsyncFunction(overrideAsyncFunction);
6343
+ }
6344
+ return cacheItem;
6345
+ }
6346
+ cacheItem = createCacheItem(
6347
+ key,
6348
+ overrideAsyncFunction ?? asyncFunction,
6349
+ options
6350
+ );
6351
+ cache.set(key, cacheItem);
6352
+ return cacheItem;
6353
+ }
6354
+ function get(key) {
6355
+ return create(key).get();
6356
+ }
6357
+ function getState(key) {
6358
+ return cache.get(key)?.getState();
6359
+ }
6360
+ function revalidate(key) {
6361
+ return create(key).revalidate();
6362
+ }
6363
+ function subscribe(key, callback) {
6364
+ return create(key).subscribe(callback) ?? noop;
6365
+ }
6366
+ function subscribeOnce(key, callback) {
6367
+ return create(key).subscribeOnce(callback) ?? noop;
6368
+ }
6369
+ function has(key) {
6370
+ return cache.has(key);
6371
+ }
6372
+ function clear() {
6373
+ cache.clear();
6374
+ }
6375
+ return {
6376
+ create,
6377
+ get,
6378
+ getState,
6379
+ revalidate,
6380
+ subscribe,
6381
+ subscribeOnce,
6382
+ has,
6383
+ clear
6384
+ };
6385
+ }
6386
+
6387
+ // src/lib/Poller.ts
6388
+ function makePoller(callback) {
6389
+ let context = {
6390
+ state: "stopped",
6391
+ timeoutHandle: null,
6392
+ interval: null,
6393
+ lastScheduledAt: null,
6394
+ remainingInterval: null
6395
+ };
6396
+ function poll() {
6397
+ if (context.state === "running") {
6398
+ schedule(context.interval);
6399
+ }
6400
+ void callback();
6401
+ }
6402
+ function schedule(interval) {
6403
+ context = {
6404
+ state: "running",
6405
+ interval: context.state !== "stopped" ? context.interval : interval,
6406
+ lastScheduledAt: performance.now(),
6407
+ timeoutHandle: setTimeout(poll, interval),
6408
+ remainingInterval: null
6409
+ };
6410
+ }
6411
+ function scheduleRemaining(remaining) {
6412
+ if (context.state !== "paused") {
6413
+ return;
6414
+ }
6415
+ context = {
6416
+ state: "running",
6417
+ interval: context.interval,
6418
+ lastScheduledAt: context.lastScheduledAt,
6419
+ timeoutHandle: setTimeout(poll, remaining),
6420
+ remainingInterval: null
6421
+ };
6422
+ }
6423
+ function start(interval) {
6424
+ if (context.state === "running") {
6425
+ return;
6426
+ }
6427
+ schedule(interval);
6428
+ }
6429
+ function restart(interval) {
6430
+ stop();
6431
+ start(interval);
6432
+ }
6433
+ function pause() {
6434
+ if (context.state !== "running") {
6435
+ return;
6436
+ }
6437
+ clearTimeout(context.timeoutHandle);
6438
+ context = {
6439
+ state: "paused",
6440
+ interval: context.interval,
6441
+ lastScheduledAt: context.lastScheduledAt,
6442
+ timeoutHandle: null,
6443
+ remainingInterval: context.interval - (performance.now() - context.lastScheduledAt)
6444
+ };
6445
+ }
6446
+ function resume() {
6447
+ if (context.state !== "paused") {
6448
+ return;
6449
+ }
6450
+ scheduleRemaining(context.remainingInterval);
6451
+ }
6452
+ function stop() {
6453
+ if (context.state === "stopped") {
6454
+ return;
6455
+ }
6456
+ if (context.timeoutHandle) {
6457
+ clearTimeout(context.timeoutHandle);
6458
+ }
6459
+ context = {
6460
+ state: "stopped",
6461
+ interval: null,
6462
+ lastScheduledAt: null,
6463
+ timeoutHandle: null,
6464
+ remainingInterval: null
6465
+ };
6466
+ }
6467
+ return {
6468
+ start,
6469
+ restart,
6470
+ pause,
6471
+ resume,
6472
+ stop
6473
+ };
6474
+ }
6475
+
6088
6476
  // src/index.ts
6089
6477
  detectDupes(PKG_NAME, PKG_VERSION, PKG_FORMAT);
6090
6478
  export {
@@ -6096,12 +6484,14 @@ export {
6096
6484
  OpCode,
6097
6485
  ServerMsgCode,
6098
6486
  WebsocketCloseCodes,
6099
- asArrayWithLegacyMethods,
6100
6487
  asPos,
6101
6488
  assert,
6102
6489
  assertNever,
6103
6490
  b64decode,
6491
+ fancy_console_exports as console,
6492
+ createAsyncCache,
6104
6493
  createClient,
6494
+ createCommentsApi,
6105
6495
  deprecate,
6106
6496
  deprecateIf,
6107
6497
  detectDupes,
@@ -6115,6 +6505,8 @@ export {
6115
6505
  isRootCrdt,
6116
6506
  legacy_patchImmutableObject,
6117
6507
  lsonToJson,
6508
+ makeEventSource,
6509
+ makePoller,
6118
6510
  makePosition,
6119
6511
  nn,
6120
6512
  patchLiveObjectKey,