@liveblocks/core 2.5.2 → 2.7.0-beta2

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.5.2";
9
+ var PKG_VERSION = "2.7.0-beta2";
10
10
  var PKG_FORMAT = "esm";
11
11
 
12
12
  // src/dupe-detection.ts
@@ -1859,8 +1859,7 @@ var Batch = class {
1859
1859
  this.clearDelayTimeout();
1860
1860
  }
1861
1861
  };
1862
- function createBatchStore(callback, options) {
1863
- const batch = new Batch(callback, options);
1862
+ function createBatchStore(batch) {
1864
1863
  const cache = /* @__PURE__ */ new Map();
1865
1864
  const eventSource2 = makeEventSource();
1866
1865
  function getCacheKey(args) {
@@ -4749,9 +4748,19 @@ function findNonSerializableValue(value, path = "") {
4749
4748
  return false;
4750
4749
  }
4751
4750
 
4751
+ // src/lib/chunk.ts
4752
+ function chunk(array, size) {
4753
+ const chunks = [];
4754
+ for (let i = 0, j = array.length; i < j; i += size) {
4755
+ chunks.push(array.slice(i, i + size));
4756
+ }
4757
+ return chunks;
4758
+ }
4759
+
4752
4760
  // src/lib/createIds.ts
4753
4761
  var THREAD_ID_PREFIX = "th";
4754
4762
  var COMMENT_ID_PREFIX = "cm";
4763
+ var COMMENT_ATTACHMENT_ID_PREFIX = "at";
4755
4764
  var INBOX_NOTIFICATION_ID_PREFIX = "in";
4756
4765
  function createOptimisticId(prefix) {
4757
4766
  return `${prefix}_${nanoid()}`;
@@ -4762,6 +4771,9 @@ function createThreadId() {
4762
4771
  function createCommentId() {
4763
4772
  return createOptimisticId(COMMENT_ID_PREFIX);
4764
4773
  }
4774
+ function createCommentAttachmentId() {
4775
+ return createOptimisticId(COMMENT_ATTACHMENT_ID_PREFIX);
4776
+ }
4765
4777
  function createInboxNotificationId() {
4766
4778
  return createOptimisticId(INBOX_NOTIFICATION_ID_PREFIX);
4767
4779
  }
@@ -5164,6 +5176,22 @@ function installBackgroundTabSpy() {
5164
5176
  };
5165
5177
  return [inBackgroundSince, unsub];
5166
5178
  }
5179
+ var GET_ATTACHMENT_URLS_BATCH_DELAY = 50;
5180
+ var ATTACHMENT_PART_SIZE = 5 * 1024 * 1024;
5181
+ var ATTACHMENT_PART_BATCH_SIZE = 5;
5182
+ function splitFileIntoParts(file) {
5183
+ const parts = [];
5184
+ let start = 0;
5185
+ while (start < file.size) {
5186
+ const end = Math.min(start + ATTACHMENT_PART_SIZE, file.size);
5187
+ parts.push({
5188
+ partNumber: parts.length + 1,
5189
+ part: file.slice(start, end)
5190
+ });
5191
+ start = end;
5192
+ }
5193
+ return parts;
5194
+ }
5167
5195
  var CommentsApiError = class extends Error {
5168
5196
  constructor(message, status, details) {
5169
5197
  super(message);
@@ -6434,7 +6462,8 @@ ${Array.from(traces).join("\n\n")}`
6434
6462
  metadata,
6435
6463
  body,
6436
6464
  commentId = createCommentId(),
6437
- threadId = createThreadId()
6465
+ threadId = createThreadId(),
6466
+ attachmentIds
6438
6467
  }) {
6439
6468
  const thread = await fetchCommentsJson("/threads", {
6440
6469
  method: "POST",
@@ -6445,7 +6474,8 @@ ${Array.from(traces).join("\n\n")}`
6445
6474
  id: threadId,
6446
6475
  comment: {
6447
6476
  id: commentId,
6448
- body
6477
+ body,
6478
+ attachmentIds
6449
6479
  },
6450
6480
  metadata
6451
6481
  })
@@ -6491,7 +6521,8 @@ ${Array.from(traces).join("\n\n")}`
6491
6521
  async function createComment({
6492
6522
  threadId,
6493
6523
  commentId = createCommentId(),
6494
- body
6524
+ body,
6525
+ attachmentIds
6495
6526
  }) {
6496
6527
  const comment = await fetchCommentsJson(
6497
6528
  `/threads/${encodeURIComponent(threadId)}/comments`,
@@ -6502,7 +6533,8 @@ ${Array.from(traces).join("\n\n")}`
6502
6533
  },
6503
6534
  body: JSON.stringify({
6504
6535
  id: commentId,
6505
- body
6536
+ body,
6537
+ attachmentIds
6506
6538
  })
6507
6539
  }
6508
6540
  );
@@ -6511,7 +6543,8 @@ ${Array.from(traces).join("\n\n")}`
6511
6543
  async function editComment({
6512
6544
  threadId,
6513
6545
  commentId,
6514
- body
6546
+ body,
6547
+ attachmentIds
6515
6548
  }) {
6516
6549
  const comment = await fetchCommentsJson(
6517
6550
  `/threads/${encodeURIComponent(threadId)}/comments/${encodeURIComponent(
@@ -6523,7 +6556,8 @@ ${Array.from(traces).join("\n\n")}`
6523
6556
  "Content-Type": "application/json"
6524
6557
  },
6525
6558
  body: JSON.stringify({
6526
- body
6559
+ body,
6560
+ attachmentIds
6527
6561
  })
6528
6562
  }
6529
6563
  );
@@ -6575,6 +6609,126 @@ ${Array.from(traces).join("\n\n")}`
6575
6609
  }
6576
6610
  );
6577
6611
  }
6612
+ function prepareAttachment(file) {
6613
+ return {
6614
+ type: "localAttachment",
6615
+ status: "idle",
6616
+ id: createCommentAttachmentId(),
6617
+ name: file.name,
6618
+ size: file.size,
6619
+ mimeType: file.type,
6620
+ file
6621
+ };
6622
+ }
6623
+ async function uploadAttachment(attachment, options2 = {}) {
6624
+ const abortSignal = options2.signal;
6625
+ const abortError = abortSignal ? new DOMException(
6626
+ `Upload of attachment ${attachment.id} was aborted.`,
6627
+ "AbortError"
6628
+ ) : void 0;
6629
+ if (abortSignal?.aborted) {
6630
+ throw abortError;
6631
+ }
6632
+ if (attachment.size <= ATTACHMENT_PART_SIZE) {
6633
+ return fetchCommentsJson(
6634
+ `/attachments/${encodeURIComponent(attachment.id)}/upload/${encodeURIComponent(attachment.name)}`,
6635
+ {
6636
+ method: "PUT",
6637
+ body: attachment.file,
6638
+ signal: abortSignal
6639
+ }
6640
+ );
6641
+ } else {
6642
+ let uploadId;
6643
+ const uploadedParts = [];
6644
+ try {
6645
+ const createMultiPartUpload = await fetchCommentsJson(
6646
+ `/attachments/${encodeURIComponent(attachment.id)}/multipart/${encodeURIComponent(attachment.name)}`,
6647
+ {
6648
+ method: "POST",
6649
+ signal: abortSignal
6650
+ }
6651
+ );
6652
+ uploadId = createMultiPartUpload.uploadId;
6653
+ const parts = splitFileIntoParts(attachment.file);
6654
+ if (abortSignal?.aborted) {
6655
+ throw abortError;
6656
+ }
6657
+ const batches = chunk(parts, ATTACHMENT_PART_BATCH_SIZE);
6658
+ for (const parts2 of batches) {
6659
+ const uploadedPartsPromises = [];
6660
+ for (const { part, partNumber } of parts2) {
6661
+ uploadedPartsPromises.push(
6662
+ fetchCommentsJson(
6663
+ `/attachments/${encodeURIComponent(attachment.id)}/multipart/${encodeURIComponent(uploadId)}/${encodeURIComponent(partNumber)}`,
6664
+ {
6665
+ method: "PUT",
6666
+ body: part,
6667
+ signal: abortSignal
6668
+ }
6669
+ )
6670
+ );
6671
+ }
6672
+ uploadedParts.push(...await Promise.all(uploadedPartsPromises));
6673
+ }
6674
+ if (abortSignal?.aborted) {
6675
+ throw abortError;
6676
+ }
6677
+ const sortedUploadedParts = uploadedParts.sort(
6678
+ (a, b) => a.partNumber - b.partNumber
6679
+ );
6680
+ return fetchCommentsJson(
6681
+ `/attachments/${encodeURIComponent(attachment.id)}/multipart/${encodeURIComponent(uploadId)}/complete`,
6682
+ {
6683
+ method: "POST",
6684
+ headers: {
6685
+ "Content-Type": "application/json"
6686
+ },
6687
+ body: JSON.stringify({ parts: sortedUploadedParts }),
6688
+ signal: abortSignal
6689
+ }
6690
+ );
6691
+ } catch (error3) {
6692
+ if (uploadId && error3?.name && (error3.name === "AbortError" || error3.name === "TimeoutError")) {
6693
+ await fetchCommentsApi(
6694
+ `/attachments/${encodeURIComponent(attachment.id)}/multipart/${encodeURIComponent(uploadId)}`,
6695
+ void 0,
6696
+ {
6697
+ method: "DELETE"
6698
+ }
6699
+ );
6700
+ }
6701
+ throw error3;
6702
+ }
6703
+ }
6704
+ }
6705
+ async function getAttachmentUrls(attachmentIds) {
6706
+ const { urls } = await fetchCommentsJson(
6707
+ "/attachments/presigned-urls",
6708
+ {
6709
+ method: "POST",
6710
+ headers: {
6711
+ "Content-Type": "application/json"
6712
+ },
6713
+ body: JSON.stringify({ attachmentIds })
6714
+ }
6715
+ );
6716
+ return urls;
6717
+ }
6718
+ const batchedGetAttachmentUrls = new Batch(
6719
+ async (batchedAttachmentIds) => {
6720
+ const attachmentIds = batchedAttachmentIds.flat();
6721
+ const attachmentUrls = await getAttachmentUrls(attachmentIds);
6722
+ return attachmentUrls.map(
6723
+ (url) => url ?? new Error("There was an error while getting this attachment's URL")
6724
+ );
6725
+ },
6726
+ { delay: GET_ATTACHMENT_URLS_BATCH_DELAY }
6727
+ );
6728
+ const attachmentUrlsStore = createBatchStore(batchedGetAttachmentUrls);
6729
+ function getAttachmentUrl(attachmentId) {
6730
+ return batchedGetAttachmentUrls.get(attachmentId);
6731
+ }
6578
6732
  async function fetchNotificationsJson(endpoint, options2) {
6579
6733
  const authValue = await delegates.authenticate();
6580
6734
  const response = await fetchClientApi(
@@ -6684,7 +6838,8 @@ ${Array.from(traces).join("\n\n")}`
6684
6838
  // These exist only for our E2E testing app
6685
6839
  explicitClose: (event) => managedSocket._privateSendMachineEvent({ type: "EXPLICIT_SOCKET_CLOSE", event }),
6686
6840
  rawSend: (data) => managedSocket.send(data)
6687
- }
6841
+ },
6842
+ attachmentUrlsStore
6688
6843
  },
6689
6844
  id: config.roomId,
6690
6845
  subscribe: makeClassicSubscribeFn(events),
@@ -6739,6 +6894,9 @@ ${Array.from(traces).join("\n\n")}`
6739
6894
  deleteComment: deleteComment2,
6740
6895
  addReaction: addReaction2,
6741
6896
  removeReaction: removeReaction2,
6897
+ prepareAttachment,
6898
+ uploadAttachment,
6899
+ getAttachmentUrl,
6742
6900
  // Notifications
6743
6901
  getNotificationSettings,
6744
6902
  updateNotificationSettings,
@@ -7282,7 +7440,8 @@ function deleteComment(thread, commentId, deletedAt) {
7282
7440
  (comment) => comment.id === commentId ? {
7283
7441
  ...comment,
7284
7442
  deletedAt,
7285
- body: void 0
7443
+ body: void 0,
7444
+ attachments: []
7286
7445
  } : comment
7287
7446
  );
7288
7447
  if (!updatedComments.some((comment) => comment.deletedAt === void 0)) {
@@ -7533,7 +7692,7 @@ function createClient(options) {
7533
7692
  () => !resolveUsers,
7534
7693
  "Set the resolveUsers option in createClient to specify user info."
7535
7694
  );
7536
- const usersStore = createBatchStore(
7695
+ const batchedResolveUsers = new Batch(
7537
7696
  async (batchedUserIds) => {
7538
7697
  const userIds = batchedUserIds.flat();
7539
7698
  const users = await resolveUsers?.({ userIds });
@@ -7542,12 +7701,13 @@ function createClient(options) {
7542
7701
  },
7543
7702
  { delay: RESOLVE_USERS_BATCH_DELAY }
7544
7703
  );
7704
+ const usersStore = createBatchStore(batchedResolveUsers);
7545
7705
  const resolveRoomsInfo = clientOptions.resolveRoomsInfo;
7546
7706
  const warnIfNoResolveRoomsInfo = createDevelopmentWarning(
7547
7707
  () => !resolveRoomsInfo,
7548
7708
  "Set the resolveRoomsInfo option in createClient to specify room info."
7549
7709
  );
7550
- const roomsInfoStore = createBatchStore(
7710
+ const batchedResolveRoomsInfo = new Batch(
7551
7711
  async (batchedRoomIds) => {
7552
7712
  const roomIds = batchedRoomIds.flat();
7553
7713
  const roomsInfo = await resolveRoomsInfo?.({ roomIds });
@@ -7556,6 +7716,7 @@ function createClient(options) {
7556
7716
  },
7557
7717
  { delay: RESOLVE_ROOMS_INFO_BATCH_DELAY }
7558
7718
  );
7719
+ const roomsInfoStore = createBatchStore(batchedResolveRoomsInfo);
7559
7720
  return Object.defineProperty(
7560
7721
  {
7561
7722
  enterRoom,
@@ -8461,6 +8622,7 @@ export {
8461
8622
  assert,
8462
8623
  assertNever,
8463
8624
  b64decode,
8625
+ chunk,
8464
8626
  cloneLson,
8465
8627
  fancy_console_exports as console,
8466
8628
  convertToCommentData,