@liveblocks/core 2.7.2 → 2.8.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.d.mts +117 -24
- package/dist/index.d.ts +117 -24
- package/dist/index.js +261 -38
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +236 -13
- package/dist/index.mjs.map +1 -1
- package/package.json +1 -1
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.
|
|
9
|
+
var PKG_VERSION = "2.8.0-beta2";
|
|
10
10
|
var PKG_FORMAT = "esm";
|
|
11
11
|
|
|
12
12
|
// src/dupe-detection.ts
|
|
@@ -1871,8 +1871,7 @@ var Batch = class {
|
|
|
1871
1871
|
this.clearDelayTimeout();
|
|
1872
1872
|
}
|
|
1873
1873
|
};
|
|
1874
|
-
function createBatchStore(
|
|
1875
|
-
const batch = new Batch(callback, options);
|
|
1874
|
+
function createBatchStore(batch) {
|
|
1876
1875
|
const cache = /* @__PURE__ */ new Map();
|
|
1877
1876
|
const eventSource2 = makeEventSource();
|
|
1878
1877
|
function getCacheKey(args) {
|
|
@@ -4796,9 +4795,41 @@ function findNonSerializableValue(value, path = "") {
|
|
|
4796
4795
|
return false;
|
|
4797
4796
|
}
|
|
4798
4797
|
|
|
4798
|
+
// src/lib/autoRetry.ts
|
|
4799
|
+
async function autoRetry(promiseFn, maxTries, backoff, exitCondition) {
|
|
4800
|
+
const fallbackBackoff = backoff.length > 0 ? backoff[backoff.length - 1] : 0;
|
|
4801
|
+
let attempt = 0;
|
|
4802
|
+
while (true) {
|
|
4803
|
+
attempt++;
|
|
4804
|
+
const promise = promiseFn();
|
|
4805
|
+
try {
|
|
4806
|
+
return await promise;
|
|
4807
|
+
} catch (err) {
|
|
4808
|
+
if (exitCondition && exitCondition(err)) {
|
|
4809
|
+
throw err;
|
|
4810
|
+
}
|
|
4811
|
+
if (attempt >= maxTries) {
|
|
4812
|
+
throw new Error(`Failed after ${maxTries} attempts: ${String(err)}`);
|
|
4813
|
+
}
|
|
4814
|
+
}
|
|
4815
|
+
const delay = backoff[attempt - 1] ?? fallbackBackoff;
|
|
4816
|
+
await wait(delay);
|
|
4817
|
+
}
|
|
4818
|
+
}
|
|
4819
|
+
|
|
4820
|
+
// src/lib/chunk.ts
|
|
4821
|
+
function chunk(array, size) {
|
|
4822
|
+
const chunks = [];
|
|
4823
|
+
for (let i = 0, j = array.length; i < j; i += size) {
|
|
4824
|
+
chunks.push(array.slice(i, i + size));
|
|
4825
|
+
}
|
|
4826
|
+
return chunks;
|
|
4827
|
+
}
|
|
4828
|
+
|
|
4799
4829
|
// src/lib/createIds.ts
|
|
4800
4830
|
var THREAD_ID_PREFIX = "th";
|
|
4801
4831
|
var COMMENT_ID_PREFIX = "cm";
|
|
4832
|
+
var COMMENT_ATTACHMENT_ID_PREFIX = "at";
|
|
4802
4833
|
var INBOX_NOTIFICATION_ID_PREFIX = "in";
|
|
4803
4834
|
function createOptimisticId(prefix) {
|
|
4804
4835
|
return `${prefix}_${nanoid()}`;
|
|
@@ -4809,6 +4840,9 @@ function createThreadId() {
|
|
|
4809
4840
|
function createCommentId() {
|
|
4810
4841
|
return createOptimisticId(COMMENT_ID_PREFIX);
|
|
4811
4842
|
}
|
|
4843
|
+
function createCommentAttachmentId() {
|
|
4844
|
+
return createOptimisticId(COMMENT_ATTACHMENT_ID_PREFIX);
|
|
4845
|
+
}
|
|
4812
4846
|
function createInboxNotificationId() {
|
|
4813
4847
|
return createOptimisticId(INBOX_NOTIFICATION_ID_PREFIX);
|
|
4814
4848
|
}
|
|
@@ -5211,6 +5245,22 @@ function installBackgroundTabSpy() {
|
|
|
5211
5245
|
};
|
|
5212
5246
|
return [inBackgroundSince, unsub];
|
|
5213
5247
|
}
|
|
5248
|
+
var GET_ATTACHMENT_URLS_BATCH_DELAY = 50;
|
|
5249
|
+
var ATTACHMENT_PART_SIZE = 5 * 1024 * 1024;
|
|
5250
|
+
var ATTACHMENT_PART_BATCH_SIZE = 5;
|
|
5251
|
+
function splitFileIntoParts(file) {
|
|
5252
|
+
const parts = [];
|
|
5253
|
+
let start = 0;
|
|
5254
|
+
while (start < file.size) {
|
|
5255
|
+
const end = Math.min(start + ATTACHMENT_PART_SIZE, file.size);
|
|
5256
|
+
parts.push({
|
|
5257
|
+
partNumber: parts.length + 1,
|
|
5258
|
+
part: file.slice(start, end)
|
|
5259
|
+
});
|
|
5260
|
+
start = end;
|
|
5261
|
+
}
|
|
5262
|
+
return parts;
|
|
5263
|
+
}
|
|
5214
5264
|
var CommentsApiError = class extends Error {
|
|
5215
5265
|
constructor(message, status, details) {
|
|
5216
5266
|
super(message);
|
|
@@ -6504,7 +6554,8 @@ ${Array.from(traces).join("\n\n")}`
|
|
|
6504
6554
|
metadata,
|
|
6505
6555
|
body,
|
|
6506
6556
|
commentId = createCommentId(),
|
|
6507
|
-
threadId = createThreadId()
|
|
6557
|
+
threadId = createThreadId(),
|
|
6558
|
+
attachmentIds
|
|
6508
6559
|
}) {
|
|
6509
6560
|
const thread = await fetchCommentsJson("/threads", {
|
|
6510
6561
|
method: "POST",
|
|
@@ -6515,7 +6566,8 @@ ${Array.from(traces).join("\n\n")}`
|
|
|
6515
6566
|
id: threadId,
|
|
6516
6567
|
comment: {
|
|
6517
6568
|
id: commentId,
|
|
6518
|
-
body
|
|
6569
|
+
body,
|
|
6570
|
+
attachmentIds
|
|
6519
6571
|
},
|
|
6520
6572
|
metadata
|
|
6521
6573
|
})
|
|
@@ -6561,7 +6613,8 @@ ${Array.from(traces).join("\n\n")}`
|
|
|
6561
6613
|
async function createComment({
|
|
6562
6614
|
threadId,
|
|
6563
6615
|
commentId = createCommentId(),
|
|
6564
|
-
body
|
|
6616
|
+
body,
|
|
6617
|
+
attachmentIds
|
|
6565
6618
|
}) {
|
|
6566
6619
|
const comment = await fetchCommentsJson(
|
|
6567
6620
|
`/threads/${encodeURIComponent(threadId)}/comments`,
|
|
@@ -6572,7 +6625,8 @@ ${Array.from(traces).join("\n\n")}`
|
|
|
6572
6625
|
},
|
|
6573
6626
|
body: JSON.stringify({
|
|
6574
6627
|
id: commentId,
|
|
6575
|
-
body
|
|
6628
|
+
body,
|
|
6629
|
+
attachmentIds
|
|
6576
6630
|
})
|
|
6577
6631
|
}
|
|
6578
6632
|
);
|
|
@@ -6581,7 +6635,8 @@ ${Array.from(traces).join("\n\n")}`
|
|
|
6581
6635
|
async function editComment({
|
|
6582
6636
|
threadId,
|
|
6583
6637
|
commentId,
|
|
6584
|
-
body
|
|
6638
|
+
body,
|
|
6639
|
+
attachmentIds
|
|
6585
6640
|
}) {
|
|
6586
6641
|
const comment = await fetchCommentsJson(
|
|
6587
6642
|
`/threads/${encodeURIComponent(threadId)}/comments/${encodeURIComponent(
|
|
@@ -6593,7 +6648,8 @@ ${Array.from(traces).join("\n\n")}`
|
|
|
6593
6648
|
"Content-Type": "application/json"
|
|
6594
6649
|
},
|
|
6595
6650
|
body: JSON.stringify({
|
|
6596
|
-
body
|
|
6651
|
+
body,
|
|
6652
|
+
attachmentIds
|
|
6597
6653
|
})
|
|
6598
6654
|
}
|
|
6599
6655
|
);
|
|
@@ -6645,6 +6701,165 @@ ${Array.from(traces).join("\n\n")}`
|
|
|
6645
6701
|
}
|
|
6646
6702
|
);
|
|
6647
6703
|
}
|
|
6704
|
+
function prepareAttachment(file) {
|
|
6705
|
+
return {
|
|
6706
|
+
type: "localAttachment",
|
|
6707
|
+
status: "idle",
|
|
6708
|
+
id: createCommentAttachmentId(),
|
|
6709
|
+
name: file.name,
|
|
6710
|
+
size: file.size,
|
|
6711
|
+
mimeType: file.type,
|
|
6712
|
+
file
|
|
6713
|
+
};
|
|
6714
|
+
}
|
|
6715
|
+
async function uploadAttachment(attachment, options2 = {}) {
|
|
6716
|
+
const abortSignal = options2.signal;
|
|
6717
|
+
const abortError = abortSignal ? new DOMException(
|
|
6718
|
+
`Upload of attachment ${attachment.id} was aborted.`,
|
|
6719
|
+
"AbortError"
|
|
6720
|
+
) : void 0;
|
|
6721
|
+
if (abortSignal?.aborted) {
|
|
6722
|
+
throw abortError;
|
|
6723
|
+
}
|
|
6724
|
+
if (attachment.size <= ATTACHMENT_PART_SIZE) {
|
|
6725
|
+
return autoRetry(
|
|
6726
|
+
() => fetchCommentsJson(
|
|
6727
|
+
`/attachments/${encodeURIComponent(attachment.id)}/upload/${encodeURIComponent(attachment.name)}`,
|
|
6728
|
+
{
|
|
6729
|
+
method: "PUT",
|
|
6730
|
+
body: attachment.file,
|
|
6731
|
+
signal: abortSignal
|
|
6732
|
+
},
|
|
6733
|
+
{
|
|
6734
|
+
fileSize: attachment.size
|
|
6735
|
+
}
|
|
6736
|
+
),
|
|
6737
|
+
10,
|
|
6738
|
+
[2e3, 2e3, 2e3, 2e3, 2e3, 2e3, 2e3, 2e3, 2e3, 2e3],
|
|
6739
|
+
() => {
|
|
6740
|
+
if (abortSignal?.aborted) {
|
|
6741
|
+
throw abortError;
|
|
6742
|
+
}
|
|
6743
|
+
return false;
|
|
6744
|
+
}
|
|
6745
|
+
);
|
|
6746
|
+
} else {
|
|
6747
|
+
let uploadId;
|
|
6748
|
+
const uploadedParts = [];
|
|
6749
|
+
const createMultiPartUpload = await autoRetry(
|
|
6750
|
+
() => fetchCommentsJson(
|
|
6751
|
+
`/attachments/${encodeURIComponent(attachment.id)}/multipart/${encodeURIComponent(attachment.name)}`,
|
|
6752
|
+
{
|
|
6753
|
+
method: "POST",
|
|
6754
|
+
signal: abortSignal
|
|
6755
|
+
},
|
|
6756
|
+
{
|
|
6757
|
+
fileSize: attachment.size
|
|
6758
|
+
}
|
|
6759
|
+
),
|
|
6760
|
+
10,
|
|
6761
|
+
[2e3, 2e3, 2e3, 2e3, 2e3, 2e3, 2e3, 2e3, 2e3, 2e3],
|
|
6762
|
+
() => {
|
|
6763
|
+
if (abortSignal?.aborted) {
|
|
6764
|
+
throw abortError;
|
|
6765
|
+
}
|
|
6766
|
+
return false;
|
|
6767
|
+
}
|
|
6768
|
+
);
|
|
6769
|
+
try {
|
|
6770
|
+
uploadId = createMultiPartUpload.uploadId;
|
|
6771
|
+
const parts = splitFileIntoParts(attachment.file);
|
|
6772
|
+
if (abortSignal?.aborted) {
|
|
6773
|
+
throw abortError;
|
|
6774
|
+
}
|
|
6775
|
+
const batches = chunk(parts, ATTACHMENT_PART_BATCH_SIZE);
|
|
6776
|
+
for (const parts2 of batches) {
|
|
6777
|
+
const uploadedPartsPromises = [];
|
|
6778
|
+
for (const { part, partNumber } of parts2) {
|
|
6779
|
+
uploadedPartsPromises.push(
|
|
6780
|
+
autoRetry(
|
|
6781
|
+
() => fetchCommentsJson(
|
|
6782
|
+
`/attachments/${encodeURIComponent(attachment.id)}/multipart/${encodeURIComponent(createMultiPartUpload.uploadId)}/${encodeURIComponent(partNumber)}`,
|
|
6783
|
+
{
|
|
6784
|
+
method: "PUT",
|
|
6785
|
+
body: part,
|
|
6786
|
+
signal: abortSignal
|
|
6787
|
+
}
|
|
6788
|
+
),
|
|
6789
|
+
10,
|
|
6790
|
+
[2e3, 2e3, 2e3, 2e3, 2e3, 2e3, 2e3, 2e3, 2e3, 2e3],
|
|
6791
|
+
() => {
|
|
6792
|
+
if (abortSignal?.aborted) {
|
|
6793
|
+
throw abortError;
|
|
6794
|
+
}
|
|
6795
|
+
return false;
|
|
6796
|
+
}
|
|
6797
|
+
)
|
|
6798
|
+
);
|
|
6799
|
+
}
|
|
6800
|
+
uploadedParts.push(...await Promise.all(uploadedPartsPromises));
|
|
6801
|
+
}
|
|
6802
|
+
if (abortSignal?.aborted) {
|
|
6803
|
+
throw abortError;
|
|
6804
|
+
}
|
|
6805
|
+
const sortedUploadedParts = uploadedParts.sort(
|
|
6806
|
+
(a, b) => a.partNumber - b.partNumber
|
|
6807
|
+
);
|
|
6808
|
+
return fetchCommentsJson(
|
|
6809
|
+
`/attachments/${encodeURIComponent(attachment.id)}/multipart/${encodeURIComponent(uploadId)}/complete`,
|
|
6810
|
+
{
|
|
6811
|
+
method: "POST",
|
|
6812
|
+
headers: {
|
|
6813
|
+
"Content-Type": "application/json"
|
|
6814
|
+
},
|
|
6815
|
+
body: JSON.stringify({ parts: sortedUploadedParts }),
|
|
6816
|
+
signal: abortSignal
|
|
6817
|
+
}
|
|
6818
|
+
);
|
|
6819
|
+
} catch (error3) {
|
|
6820
|
+
if (uploadId && error3?.name && (error3.name === "AbortError" || error3.name === "TimeoutError")) {
|
|
6821
|
+
try {
|
|
6822
|
+
await fetchCommentsApi(
|
|
6823
|
+
`/attachments/${encodeURIComponent(attachment.id)}/multipart/${encodeURIComponent(uploadId)}`,
|
|
6824
|
+
void 0,
|
|
6825
|
+
{
|
|
6826
|
+
method: "DELETE"
|
|
6827
|
+
}
|
|
6828
|
+
);
|
|
6829
|
+
} catch (error4) {
|
|
6830
|
+
}
|
|
6831
|
+
}
|
|
6832
|
+
throw error3;
|
|
6833
|
+
}
|
|
6834
|
+
}
|
|
6835
|
+
}
|
|
6836
|
+
async function getAttachmentUrls(attachmentIds) {
|
|
6837
|
+
const { urls } = await fetchCommentsJson(
|
|
6838
|
+
"/attachments/presigned-urls",
|
|
6839
|
+
{
|
|
6840
|
+
method: "POST",
|
|
6841
|
+
headers: {
|
|
6842
|
+
"Content-Type": "application/json"
|
|
6843
|
+
},
|
|
6844
|
+
body: JSON.stringify({ attachmentIds })
|
|
6845
|
+
}
|
|
6846
|
+
);
|
|
6847
|
+
return urls;
|
|
6848
|
+
}
|
|
6849
|
+
const batchedGetAttachmentUrls = new Batch(
|
|
6850
|
+
async (batchedAttachmentIds) => {
|
|
6851
|
+
const attachmentIds = batchedAttachmentIds.flat();
|
|
6852
|
+
const attachmentUrls = await getAttachmentUrls(attachmentIds);
|
|
6853
|
+
return attachmentUrls.map(
|
|
6854
|
+
(url) => url ?? new Error("There was an error while getting this attachment's URL")
|
|
6855
|
+
);
|
|
6856
|
+
},
|
|
6857
|
+
{ delay: GET_ATTACHMENT_URLS_BATCH_DELAY }
|
|
6858
|
+
);
|
|
6859
|
+
const attachmentUrlsStore = createBatchStore(batchedGetAttachmentUrls);
|
|
6860
|
+
function getAttachmentUrl(attachmentId) {
|
|
6861
|
+
return batchedGetAttachmentUrls.get(attachmentId);
|
|
6862
|
+
}
|
|
6648
6863
|
async function fetchNotificationsJson(endpoint, options2) {
|
|
6649
6864
|
const authValue = await delegates.authenticate();
|
|
6650
6865
|
const response = await fetchClientApi(
|
|
@@ -6760,7 +6975,8 @@ ${Array.from(traces).join("\n\n")}`
|
|
|
6760
6975
|
// These exist only for our E2E testing app
|
|
6761
6976
|
explicitClose: (event) => managedSocket._privateSendMachineEvent({ type: "EXPLICIT_SOCKET_CLOSE", event }),
|
|
6762
6977
|
rawSend: (data) => managedSocket.send(data)
|
|
6763
|
-
}
|
|
6978
|
+
},
|
|
6979
|
+
attachmentUrlsStore
|
|
6764
6980
|
},
|
|
6765
6981
|
id: config.roomId,
|
|
6766
6982
|
subscribe: makeClassicSubscribeFn(events),
|
|
@@ -6815,6 +7031,9 @@ ${Array.from(traces).join("\n\n")}`
|
|
|
6815
7031
|
deleteComment,
|
|
6816
7032
|
addReaction,
|
|
6817
7033
|
removeReaction,
|
|
7034
|
+
prepareAttachment,
|
|
7035
|
+
uploadAttachment,
|
|
7036
|
+
getAttachmentUrl,
|
|
6818
7037
|
// Notifications
|
|
6819
7038
|
getNotificationSettings,
|
|
6820
7039
|
updateNotificationSettings,
|
|
@@ -7095,7 +7314,7 @@ function createClient(options) {
|
|
|
7095
7314
|
() => !resolveUsers,
|
|
7096
7315
|
"Set the resolveUsers option in createClient to specify user info."
|
|
7097
7316
|
);
|
|
7098
|
-
const
|
|
7317
|
+
const batchedResolveUsers = new Batch(
|
|
7099
7318
|
async (batchedUserIds) => {
|
|
7100
7319
|
const userIds = batchedUserIds.flat();
|
|
7101
7320
|
const users = await resolveUsers?.({ userIds });
|
|
@@ -7104,12 +7323,13 @@ function createClient(options) {
|
|
|
7104
7323
|
},
|
|
7105
7324
|
{ delay: RESOLVE_USERS_BATCH_DELAY }
|
|
7106
7325
|
);
|
|
7326
|
+
const usersStore = createBatchStore(batchedResolveUsers);
|
|
7107
7327
|
const resolveRoomsInfo = clientOptions.resolveRoomsInfo;
|
|
7108
7328
|
const warnIfNoResolveRoomsInfo = createDevelopmentWarning(
|
|
7109
7329
|
() => !resolveRoomsInfo,
|
|
7110
7330
|
"Set the resolveRoomsInfo option in createClient to specify room info."
|
|
7111
7331
|
);
|
|
7112
|
-
const
|
|
7332
|
+
const batchedResolveRoomsInfo = new Batch(
|
|
7113
7333
|
async (batchedRoomIds) => {
|
|
7114
7334
|
const roomIds = batchedRoomIds.flat();
|
|
7115
7335
|
const roomsInfo = await resolveRoomsInfo?.({ roomIds });
|
|
@@ -7118,6 +7338,7 @@ function createClient(options) {
|
|
|
7118
7338
|
},
|
|
7119
7339
|
{ delay: RESOLVE_ROOMS_INFO_BATCH_DELAY }
|
|
7120
7340
|
);
|
|
7341
|
+
const roomsInfoStore = createBatchStore(batchedResolveRoomsInfo);
|
|
7121
7342
|
return Object.defineProperty(
|
|
7122
7343
|
{
|
|
7123
7344
|
enterRoom,
|
|
@@ -7203,7 +7424,7 @@ function createDevelopmentWarning(condition, ...args) {
|
|
|
7203
7424
|
|
|
7204
7425
|
// src/comments/comment-body.ts
|
|
7205
7426
|
function isCommentBodyParagraph(element) {
|
|
7206
|
-
return "type" in element && element.type === "
|
|
7427
|
+
return "type" in element && element.type === "mention";
|
|
7207
7428
|
}
|
|
7208
7429
|
function isCommentBodyText(element) {
|
|
7209
7430
|
return !("type" in element) && "text" in element && typeof element.text === "string";
|
|
@@ -8019,7 +8240,9 @@ export {
|
|
|
8019
8240
|
asPos,
|
|
8020
8241
|
assert,
|
|
8021
8242
|
assertNever,
|
|
8243
|
+
autoRetry,
|
|
8022
8244
|
b64decode,
|
|
8245
|
+
chunk,
|
|
8023
8246
|
cloneLson,
|
|
8024
8247
|
compactObject,
|
|
8025
8248
|
fancy_console_exports as console,
|