@liveblocks/core 1.2.2-comments3 → 1.2.2-comments5

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.2-comments3";
9
+ var PKG_VERSION = "1.2.2-comments5";
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
  }
@@ -1649,6 +1670,149 @@ function errorIf(condition, message) {
1649
1670
  }
1650
1671
  }
1651
1672
 
1673
+ // src/comments/index.ts
1674
+ function getAuthBearerHeaderFromAuthValue(authValue) {
1675
+ if (authValue.type === "public") {
1676
+ return authValue.publicApiKey;
1677
+ } else {
1678
+ return authValue.token.raw;
1679
+ }
1680
+ }
1681
+ function createCommentsApi(roomId, getAuthValue, { serverEndpoint }) {
1682
+ async function fetchJson(endpoint, options) {
1683
+ const response = await fetchApi(roomId, endpoint, options);
1684
+ if (!response.ok) {
1685
+ if (response.status >= 400 && response.status < 600) {
1686
+ let errorMessage = "";
1687
+ try {
1688
+ const errorBody = await response.json();
1689
+ errorMessage = errorBody.message;
1690
+ } catch (error3) {
1691
+ errorMessage = response.statusText;
1692
+ }
1693
+ throw new Error(
1694
+ `Request failed with status ${response.status}: ${errorMessage}`
1695
+ );
1696
+ }
1697
+ }
1698
+ let body;
1699
+ try {
1700
+ body = await response.json();
1701
+ } catch {
1702
+ body = {};
1703
+ }
1704
+ return body;
1705
+ }
1706
+ async function fetchApi(roomId2, endpoint, options) {
1707
+ const authValue = await getAuthValue();
1708
+ const url = `${serverEndpoint}/c/rooms/${roomId2}${endpoint}`;
1709
+ return await fetch(url, {
1710
+ ...options,
1711
+ headers: {
1712
+ ...options?.headers,
1713
+ Authorization: `Bearer ${getAuthBearerHeaderFromAuthValue(authValue)}`
1714
+ }
1715
+ });
1716
+ }
1717
+ async function getThreads() {
1718
+ const response = await fetchApi(roomId, "/threads");
1719
+ if (response.ok) {
1720
+ const json = await response.json();
1721
+ return json.data;
1722
+ } else if (response.status === 404) {
1723
+ return [];
1724
+ } else {
1725
+ throw new Error("FAIL");
1726
+ }
1727
+ }
1728
+ function createThread({
1729
+ metadata,
1730
+ body,
1731
+ commentId,
1732
+ threadId
1733
+ }) {
1734
+ return fetchJson("/threads", {
1735
+ method: "POST",
1736
+ headers: {
1737
+ "Content-Type": "application/json"
1738
+ },
1739
+ body: JSON.stringify({
1740
+ id: threadId,
1741
+ comment: {
1742
+ id: commentId,
1743
+ body
1744
+ },
1745
+ metadata
1746
+ })
1747
+ });
1748
+ }
1749
+ function editThreadMetadata({
1750
+ metadata,
1751
+ threadId
1752
+ }) {
1753
+ return fetchJson(
1754
+ `/threads/${threadId}/metadata`,
1755
+ {
1756
+ method: "POST",
1757
+ headers: {
1758
+ "Content-Type": "application/json"
1759
+ },
1760
+ body: JSON.stringify(metadata)
1761
+ }
1762
+ );
1763
+ }
1764
+ function createComment({
1765
+ threadId,
1766
+ commentId,
1767
+ body
1768
+ }) {
1769
+ return fetchJson(`/threads/${threadId}/comments`, {
1770
+ method: "POST",
1771
+ headers: {
1772
+ "Content-Type": "application/json"
1773
+ },
1774
+ body: JSON.stringify({
1775
+ id: commentId,
1776
+ body
1777
+ })
1778
+ });
1779
+ }
1780
+ function editComment({
1781
+ threadId,
1782
+ commentId,
1783
+ body
1784
+ }) {
1785
+ return fetchJson(
1786
+ `/threads/${threadId}/comments/${commentId}`,
1787
+ {
1788
+ method: "POST",
1789
+ headers: {
1790
+ "Content-Type": "application/json"
1791
+ },
1792
+ body: JSON.stringify({
1793
+ body
1794
+ })
1795
+ }
1796
+ );
1797
+ }
1798
+ async function deleteComment({
1799
+ threadId,
1800
+ commentId
1801
+ }) {
1802
+ await fetchJson(`/threads/${threadId}/comments/${commentId}`, {
1803
+ method: "DELETE"
1804
+ });
1805
+ }
1806
+ return {
1807
+ getThreads,
1808
+ createThread,
1809
+ editThreadMetadata,
1810
+ createComment,
1811
+ editComment,
1812
+ deleteComment
1813
+ };
1814
+ }
1815
+
1652
1816
  // src/lib/position.ts
1653
1817
  var MIN_CODE = 32;
1654
1818
  var MAX_CODE = 126;
@@ -4251,6 +4415,7 @@ function makeUser(conn, presence) {
4251
4415
  id,
4252
4416
  info,
4253
4417
  canWrite,
4418
+ canComment: canComment(conn.scopes),
4254
4419
  isReadOnly: !canWrite,
4255
4420
  // Deprecated, kept for backward-compatibility
4256
4421
  presence
@@ -4638,7 +4803,8 @@ function createRoom(options, config) {
4638
4803
  history: makeEventSource(),
4639
4804
  storageDidLoad: makeEventSource(),
4640
4805
  storageStatus: makeEventSource(),
4641
- ydoc: makeEventSource()
4806
+ ydoc: makeEventSource(),
4807
+ comments: makeEventSource()
4642
4808
  };
4643
4809
  function sendMessages(messageOrMessages) {
4644
4810
  const message = JSON.stringify(messageOrMessages);
@@ -4679,6 +4845,7 @@ function createRoom(options, config) {
4679
4845
  info: staticSession.userInfo,
4680
4846
  presence: myPresence,
4681
4847
  canWrite,
4848
+ canComment: canComment(dynamicSession.scopes),
4682
4849
  isReadOnly: !canWrite
4683
4850
  // Deprecated, kept for backward-compatibility
4684
4851
  };
@@ -5135,6 +5302,14 @@ ${Array.from(traces).join("\n\n")}`
5135
5302
  }
5136
5303
  break;
5137
5304
  }
5305
+ case 400 /* THREAD_CREATED */:
5306
+ case 401 /* THREAD_METADATA_UPDATED */:
5307
+ case 402 /* COMMENT_CREATED */:
5308
+ case 403 /* COMMENT_EDITED */:
5309
+ case 404 /* COMMENT_DELETED */: {
5310
+ eventHub.comments.notify(message);
5311
+ break;
5312
+ }
5138
5313
  }
5139
5314
  }
5140
5315
  notify(updates, doNotBatchUpdates);
@@ -5401,8 +5576,12 @@ ${Array.from(traces).join("\n\n")}`
5401
5576
  history: eventHub.history.observable,
5402
5577
  storageDidLoad: eventHub.storageDidLoad.observable,
5403
5578
  storageStatus: eventHub.storageStatus.observable,
5404
- ydoc: eventHub.ydoc.observable
5579
+ ydoc: eventHub.ydoc.observable,
5580
+ comments: eventHub.comments.observable
5405
5581
  };
5582
+ const commentsApi = createCommentsApi(config.roomId, delegates.authenticate, {
5583
+ serverEndpoint: "https://api.liveblocks.io/v2"
5584
+ });
5406
5585
  return Object.defineProperty(
5407
5586
  {
5408
5587
  /* NOTE: Exposing __internal here only to allow testing implementation details in unit tests */
@@ -5460,7 +5639,8 @@ ${Array.from(traces).join("\n\n")}`
5460
5639
  getSelf: () => self.current,
5461
5640
  // Presence
5462
5641
  getPresence: () => context.myPresence.current,
5463
- getOthers: () => context.others.current
5642
+ getOthers: () => context.others.current,
5643
+ ...commentsApi
5464
5644
  },
5465
5645
  // Explictly make the __internal field non-enumerable, to avoid aggressive
5466
5646
  // freezing when used with Immer
@@ -6085,6 +6265,222 @@ function shallow(a, b) {
6085
6265
  return shallowObj(a, b);
6086
6266
  }
6087
6267
 
6268
+ // src/lib/AsyncCache.ts
6269
+ var noop = () => {
6270
+ };
6271
+ function isShallowEqual(a, b) {
6272
+ if (a.isLoading !== b.isLoading || a.data === void 0 !== (b.data === void 0) || a.error === void 0 !== (b.error === void 0)) {
6273
+ return false;
6274
+ } else {
6275
+ return shallow(a.data, b.data) && shallow(a.error, b.error);
6276
+ }
6277
+ }
6278
+ function createCacheItem(key, defaultAsyncFunction, options) {
6279
+ let asyncFunction = defaultAsyncFunction;
6280
+ const context = {
6281
+ isInvalid: true
6282
+ };
6283
+ let state = { isLoading: false };
6284
+ let previousState = { isLoading: false };
6285
+ const eventSource2 = makeEventSource();
6286
+ function notify() {
6287
+ const isEqual = options?.isStateEqual ?? isShallowEqual;
6288
+ if (!isEqual(previousState, state)) {
6289
+ previousState = state;
6290
+ eventSource2.notify(state);
6291
+ }
6292
+ }
6293
+ async function resolve() {
6294
+ if (!context.promise) {
6295
+ return;
6296
+ }
6297
+ try {
6298
+ const data = await context.promise;
6299
+ context.isInvalid = false;
6300
+ state = {
6301
+ isLoading: false,
6302
+ data
6303
+ };
6304
+ } catch (error3) {
6305
+ state = {
6306
+ isLoading: false,
6307
+ data: state.data,
6308
+ error: error3
6309
+ };
6310
+ }
6311
+ context.promise = void 0;
6312
+ notify();
6313
+ }
6314
+ async function revalidate() {
6315
+ context.isInvalid = true;
6316
+ return get();
6317
+ }
6318
+ async function get() {
6319
+ if (context.isInvalid) {
6320
+ if (!context.promise) {
6321
+ context.isInvalid = true;
6322
+ context.promise = asyncFunction(key);
6323
+ state = { isLoading: true, data: state.data };
6324
+ notify();
6325
+ }
6326
+ await resolve();
6327
+ }
6328
+ return getState();
6329
+ }
6330
+ function getState() {
6331
+ return state;
6332
+ }
6333
+ function setAsyncFunction(overrideAsyncFunction) {
6334
+ asyncFunction = overrideAsyncFunction;
6335
+ }
6336
+ return {
6337
+ ...eventSource2.observable,
6338
+ setAsyncFunction,
6339
+ get,
6340
+ getState,
6341
+ revalidate
6342
+ };
6343
+ }
6344
+ function createAsyncCache(asyncFunction, options) {
6345
+ const cache = /* @__PURE__ */ new Map();
6346
+ function create(key, overrideAsyncFunction) {
6347
+ let cacheItem = cache.get(key);
6348
+ if (cacheItem) {
6349
+ if (overrideAsyncFunction) {
6350
+ cacheItem.setAsyncFunction(overrideAsyncFunction);
6351
+ }
6352
+ return cacheItem;
6353
+ }
6354
+ cacheItem = createCacheItem(
6355
+ key,
6356
+ overrideAsyncFunction ?? asyncFunction,
6357
+ options
6358
+ );
6359
+ cache.set(key, cacheItem);
6360
+ return cacheItem;
6361
+ }
6362
+ function get(key) {
6363
+ return create(key).get();
6364
+ }
6365
+ function getState(key) {
6366
+ return cache.get(key)?.getState();
6367
+ }
6368
+ function revalidate(key) {
6369
+ return create(key).revalidate();
6370
+ }
6371
+ function subscribe(key, callback) {
6372
+ return create(key).subscribe(callback) ?? noop;
6373
+ }
6374
+ function subscribeOnce(key, callback) {
6375
+ return create(key).subscribeOnce(callback) ?? noop;
6376
+ }
6377
+ function has(key) {
6378
+ return cache.has(key);
6379
+ }
6380
+ function clear() {
6381
+ cache.clear();
6382
+ }
6383
+ return {
6384
+ create,
6385
+ get,
6386
+ getState,
6387
+ revalidate,
6388
+ subscribe,
6389
+ subscribeOnce,
6390
+ has,
6391
+ clear
6392
+ };
6393
+ }
6394
+
6395
+ // src/lib/Poller.ts
6396
+ function makePoller(callback) {
6397
+ let context = {
6398
+ state: "stopped",
6399
+ timeoutHandle: null,
6400
+ interval: null,
6401
+ lastScheduledAt: null,
6402
+ remainingInterval: null
6403
+ };
6404
+ function poll() {
6405
+ if (context.state === "running") {
6406
+ schedule(context.interval);
6407
+ }
6408
+ callback();
6409
+ }
6410
+ function schedule(interval) {
6411
+ context = {
6412
+ state: "running",
6413
+ interval: context.state !== "stopped" ? context.interval : interval,
6414
+ lastScheduledAt: performance.now(),
6415
+ timeoutHandle: setTimeout(poll, interval),
6416
+ remainingInterval: null
6417
+ };
6418
+ }
6419
+ function scheduleRemaining(remaining) {
6420
+ if (context.state !== "paused") {
6421
+ return;
6422
+ }
6423
+ context = {
6424
+ state: "running",
6425
+ interval: context.interval,
6426
+ lastScheduledAt: context.lastScheduledAt,
6427
+ timeoutHandle: setTimeout(poll, remaining),
6428
+ remainingInterval: null
6429
+ };
6430
+ }
6431
+ function start(interval) {
6432
+ if (context.state === "running") {
6433
+ return;
6434
+ }
6435
+ schedule(interval);
6436
+ }
6437
+ function restart(interval) {
6438
+ stop();
6439
+ start(interval);
6440
+ }
6441
+ function pause() {
6442
+ if (context.state !== "running") {
6443
+ return;
6444
+ }
6445
+ clearTimeout(context.timeoutHandle);
6446
+ context = {
6447
+ state: "paused",
6448
+ interval: context.interval,
6449
+ lastScheduledAt: context.lastScheduledAt,
6450
+ timeoutHandle: null,
6451
+ remainingInterval: context.interval - (performance.now() - context.lastScheduledAt)
6452
+ };
6453
+ }
6454
+ function resume() {
6455
+ if (context.state !== "paused") {
6456
+ return;
6457
+ }
6458
+ scheduleRemaining(context.remainingInterval);
6459
+ }
6460
+ function stop() {
6461
+ if (context.state === "stopped") {
6462
+ return;
6463
+ }
6464
+ if (context.timeoutHandle) {
6465
+ clearTimeout(context.timeoutHandle);
6466
+ }
6467
+ context = {
6468
+ state: "stopped",
6469
+ interval: null,
6470
+ lastScheduledAt: null,
6471
+ timeoutHandle: null,
6472
+ remainingInterval: null
6473
+ };
6474
+ }
6475
+ return {
6476
+ start,
6477
+ restart,
6478
+ pause,
6479
+ resume,
6480
+ stop
6481
+ };
6482
+ }
6483
+
6088
6484
  // src/index.ts
6089
6485
  detectDupes(PKG_NAME, PKG_VERSION, PKG_FORMAT);
6090
6486
  export {
@@ -6101,7 +6497,10 @@ export {
6101
6497
  assert,
6102
6498
  assertNever,
6103
6499
  b64decode,
6500
+ fancy_console_exports as console,
6501
+ createAsyncCache,
6104
6502
  createClient,
6503
+ createCommentsApi,
6105
6504
  deprecate,
6106
6505
  deprecateIf,
6107
6506
  detectDupes,
@@ -6115,6 +6514,8 @@ export {
6115
6514
  isRootCrdt,
6116
6515
  legacy_patchImmutableObject,
6117
6516
  lsonToJson,
6517
+ makeEventSource,
6518
+ makePoller,
6118
6519
  makePosition,
6119
6520
  nn,
6120
6521
  patchLiveObjectKey,