@liveblocks/core 2.24.0 → 2.25.0-aiprivatebeta0
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.cjs +1332 -260
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +2740 -2321
- package/dist/index.d.ts +2740 -2321
- package/dist/index.js +1254 -182
- package/dist/index.js.map +1 -1
- package/package.json +2 -1
package/dist/index.js
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.25.0-aiprivatebeta0";
|
|
10
10
|
var PKG_FORMAT = "esm";
|
|
11
11
|
|
|
12
12
|
// src/dupe-detection.ts
|
|
@@ -1110,6 +1110,7 @@ function url(strings, ...values2) {
|
|
|
1110
1110
|
function createApiClient({
|
|
1111
1111
|
baseUrl,
|
|
1112
1112
|
authManager,
|
|
1113
|
+
currentUserId,
|
|
1113
1114
|
fetchPolyfill
|
|
1114
1115
|
}) {
|
|
1115
1116
|
const httpClient = new HttpClient(baseUrl, fetchPolyfill);
|
|
@@ -1530,6 +1531,103 @@ function createApiClient({
|
|
|
1530
1531
|
const batch2 = getOrCreateAttachmentUrlsStore(options.roomId).batch;
|
|
1531
1532
|
return batch2.get(options.attachmentId);
|
|
1532
1533
|
}
|
|
1534
|
+
async function uploadChatAttachment(options) {
|
|
1535
|
+
const { chatId, attachment, signal } = options;
|
|
1536
|
+
const userId = currentUserId.get();
|
|
1537
|
+
if (userId === void 0) {
|
|
1538
|
+
throw new Error("Attachment upload requires an authenticated user.");
|
|
1539
|
+
}
|
|
1540
|
+
const ATTACHMENT_PART_SIZE = 5 * 1024 * 1024;
|
|
1541
|
+
if (options.attachment.file.size <= ATTACHMENT_PART_SIZE) {
|
|
1542
|
+
await httpClient.putBlob(
|
|
1543
|
+
url`/v2/c/chats/${chatId}/attachments/${attachment.id}/upload/${encodeURIComponent(attachment.file.name)}`,
|
|
1544
|
+
await authManager.getAuthValue({ requestedScope: "comments:read" }),
|
|
1545
|
+
attachment.file,
|
|
1546
|
+
{ fileSize: attachment.file.size },
|
|
1547
|
+
{ signal }
|
|
1548
|
+
);
|
|
1549
|
+
} else {
|
|
1550
|
+
const multipartUpload = await httpClient.post(
|
|
1551
|
+
url`/v2/c/chats/${chatId}/attachments/${attachment.id}/multipart/${encodeURIComponent(attachment.file.name)}`,
|
|
1552
|
+
await authManager.getAuthValue({ requestedScope: "comments:read" }),
|
|
1553
|
+
void 0,
|
|
1554
|
+
{ signal },
|
|
1555
|
+
{ fileSize: attachment.file.size }
|
|
1556
|
+
);
|
|
1557
|
+
try {
|
|
1558
|
+
const uploadedParts = [];
|
|
1559
|
+
const parts = [];
|
|
1560
|
+
let start = 0;
|
|
1561
|
+
while (start < attachment.file.size) {
|
|
1562
|
+
const end = Math.min(
|
|
1563
|
+
start + ATTACHMENT_PART_SIZE,
|
|
1564
|
+
attachment.file.size
|
|
1565
|
+
);
|
|
1566
|
+
parts.push({
|
|
1567
|
+
number: parts.length + 1,
|
|
1568
|
+
part: attachment.file.slice(start, end)
|
|
1569
|
+
});
|
|
1570
|
+
start = end;
|
|
1571
|
+
}
|
|
1572
|
+
uploadedParts.push(
|
|
1573
|
+
...await Promise.all(
|
|
1574
|
+
parts.map(async ({ number, part }) => {
|
|
1575
|
+
return await httpClient.putBlob(
|
|
1576
|
+
url`/v2/c/chats/${chatId}/attachments/${attachment.id}/multipart/${multipartUpload.uploadId}/${String(number)}`,
|
|
1577
|
+
await authManager.getAuthValue({
|
|
1578
|
+
requestedScope: "comments:read"
|
|
1579
|
+
}),
|
|
1580
|
+
part,
|
|
1581
|
+
void 0,
|
|
1582
|
+
{ signal }
|
|
1583
|
+
);
|
|
1584
|
+
})
|
|
1585
|
+
)
|
|
1586
|
+
);
|
|
1587
|
+
await httpClient.post(
|
|
1588
|
+
url`/v2/c/chats/${chatId}/attachments/${attachment.id}/multipart/${multipartUpload.uploadId}/complete`,
|
|
1589
|
+
await authManager.getAuthValue({ requestedScope: "comments:read" }),
|
|
1590
|
+
{ parts: uploadedParts.sort((a, b) => a.number - b.number) },
|
|
1591
|
+
{ signal }
|
|
1592
|
+
);
|
|
1593
|
+
} catch (err) {
|
|
1594
|
+
try {
|
|
1595
|
+
await httpClient.delete(
|
|
1596
|
+
url`/v2/c/chats/${chatId}/attachments/${attachment.id}/multipart/${multipartUpload.uploadId}`,
|
|
1597
|
+
await authManager.getAuthValue({ requestedScope: "comments:read" })
|
|
1598
|
+
);
|
|
1599
|
+
} catch (err2) {
|
|
1600
|
+
}
|
|
1601
|
+
throw err;
|
|
1602
|
+
}
|
|
1603
|
+
}
|
|
1604
|
+
}
|
|
1605
|
+
const attachmentUrlsBatchStoresByChat = new DefaultMap((chatId) => {
|
|
1606
|
+
const batch2 = new Batch(
|
|
1607
|
+
async (batchedAttachmentIds) => {
|
|
1608
|
+
const attachmentIds = batchedAttachmentIds.flat();
|
|
1609
|
+
const { urls } = await httpClient.post(
|
|
1610
|
+
url`/v2/c/chats/${chatId}/attachments/presigned-urls`,
|
|
1611
|
+
await authManager.getAuthValue({
|
|
1612
|
+
requestedScope: "comments:read"
|
|
1613
|
+
}),
|
|
1614
|
+
{ attachmentIds }
|
|
1615
|
+
);
|
|
1616
|
+
return urls.map(
|
|
1617
|
+
(url2) => url2 ?? new Error("There was an error while getting this attachment's URL")
|
|
1618
|
+
);
|
|
1619
|
+
},
|
|
1620
|
+
{ delay: 50 }
|
|
1621
|
+
);
|
|
1622
|
+
return createBatchStore(batch2);
|
|
1623
|
+
});
|
|
1624
|
+
function getOrCreateChatAttachmentUrlsStore(chatId) {
|
|
1625
|
+
return attachmentUrlsBatchStoresByChat.getOrCreate(chatId);
|
|
1626
|
+
}
|
|
1627
|
+
function getChatAttachmentUrl(options) {
|
|
1628
|
+
const batch2 = getOrCreateChatAttachmentUrlsStore(options.chatId).batch;
|
|
1629
|
+
return batch2.get(options.attachmentId);
|
|
1630
|
+
}
|
|
1533
1631
|
async function getSubscriptionSettings(options) {
|
|
1534
1632
|
return httpClient.get(
|
|
1535
1633
|
url`/v2/c/rooms/${options.roomId}/subscription-settings`,
|
|
@@ -1904,6 +2002,10 @@ function createApiClient({
|
|
|
1904
2002
|
getAttachmentUrl,
|
|
1905
2003
|
uploadAttachment,
|
|
1906
2004
|
getOrCreateAttachmentUrlsStore,
|
|
2005
|
+
// User attachments
|
|
2006
|
+
uploadChatAttachment,
|
|
2007
|
+
getOrCreateChatAttachmentUrlsStore,
|
|
2008
|
+
getChatAttachmentUrl,
|
|
1907
2009
|
// Room storage
|
|
1908
2010
|
streamStorage,
|
|
1909
2011
|
sendMessages,
|
|
@@ -3165,62 +3267,1132 @@ var ManagedSocket = class {
|
|
|
3165
3267
|
while (cleanup = this.#cleanups.pop()) {
|
|
3166
3268
|
cleanup();
|
|
3167
3269
|
}
|
|
3168
|
-
}
|
|
3169
|
-
/**
|
|
3170
|
-
* Safely send a message to the current WebSocket connection. Will emit a log
|
|
3171
|
-
* message if this is somehow impossible.
|
|
3172
|
-
*/
|
|
3173
|
-
send(data) {
|
|
3174
|
-
const socket = this.#machine.context?.socket;
|
|
3175
|
-
if (socket === null) {
|
|
3176
|
-
warn("Cannot send: not connected yet", data);
|
|
3177
|
-
} else if (socket.readyState !== 1) {
|
|
3178
|
-
warn("Cannot send: WebSocket no longer open", data);
|
|
3179
|
-
} else {
|
|
3180
|
-
socket.send(data);
|
|
3270
|
+
}
|
|
3271
|
+
/**
|
|
3272
|
+
* Safely send a message to the current WebSocket connection. Will emit a log
|
|
3273
|
+
* message if this is somehow impossible.
|
|
3274
|
+
*/
|
|
3275
|
+
send(data) {
|
|
3276
|
+
const socket = this.#machine.context?.socket;
|
|
3277
|
+
if (socket === null) {
|
|
3278
|
+
warn("Cannot send: not connected yet", data);
|
|
3279
|
+
} else if (socket.readyState !== 1) {
|
|
3280
|
+
warn("Cannot send: WebSocket no longer open", data);
|
|
3281
|
+
} else {
|
|
3282
|
+
socket.send(data);
|
|
3283
|
+
}
|
|
3284
|
+
}
|
|
3285
|
+
/**
|
|
3286
|
+
* NOTE: Used by the E2E app only, to simulate explicit events.
|
|
3287
|
+
* Not ideal to keep exposed :(
|
|
3288
|
+
*/
|
|
3289
|
+
_privateSendMachineEvent(event) {
|
|
3290
|
+
this.#machine.send(event);
|
|
3291
|
+
}
|
|
3292
|
+
};
|
|
3293
|
+
|
|
3294
|
+
// src/internal.ts
|
|
3295
|
+
var kInternal = Symbol();
|
|
3296
|
+
|
|
3297
|
+
// src/lib/shallow.ts
|
|
3298
|
+
function shallowArray(xs, ys) {
|
|
3299
|
+
if (xs.length !== ys.length) {
|
|
3300
|
+
return false;
|
|
3301
|
+
}
|
|
3302
|
+
for (let i = 0; i < xs.length; i++) {
|
|
3303
|
+
if (!Object.is(xs[i], ys[i])) {
|
|
3304
|
+
return false;
|
|
3305
|
+
}
|
|
3306
|
+
}
|
|
3307
|
+
return true;
|
|
3308
|
+
}
|
|
3309
|
+
function shallowObj(objA, objB) {
|
|
3310
|
+
if (!isPlainObject(objA) || !isPlainObject(objB)) {
|
|
3311
|
+
return false;
|
|
3312
|
+
}
|
|
3313
|
+
const keysA = Object.keys(objA);
|
|
3314
|
+
if (keysA.length !== Object.keys(objB).length) {
|
|
3315
|
+
return false;
|
|
3316
|
+
}
|
|
3317
|
+
return keysA.every(
|
|
3318
|
+
(key) => Object.prototype.hasOwnProperty.call(objB, key) && Object.is(objA[key], objB[key])
|
|
3319
|
+
);
|
|
3320
|
+
}
|
|
3321
|
+
function shallow(a, b) {
|
|
3322
|
+
if (Object.is(a, b)) {
|
|
3323
|
+
return true;
|
|
3324
|
+
}
|
|
3325
|
+
const isArrayA = Array.isArray(a);
|
|
3326
|
+
const isArrayB = Array.isArray(b);
|
|
3327
|
+
if (isArrayA || isArrayB) {
|
|
3328
|
+
if (!isArrayA || !isArrayB) {
|
|
3329
|
+
return false;
|
|
3330
|
+
}
|
|
3331
|
+
return shallowArray(a, b);
|
|
3332
|
+
}
|
|
3333
|
+
return shallowObj(a, b);
|
|
3334
|
+
}
|
|
3335
|
+
function shallow2(a, b) {
|
|
3336
|
+
if (!isPlainObject(a) || !isPlainObject(b)) {
|
|
3337
|
+
return shallow(a, b);
|
|
3338
|
+
}
|
|
3339
|
+
const keysA = Object.keys(a);
|
|
3340
|
+
if (keysA.length !== Object.keys(b).length) {
|
|
3341
|
+
return false;
|
|
3342
|
+
}
|
|
3343
|
+
return keysA.every(
|
|
3344
|
+
(key) => Object.prototype.hasOwnProperty.call(b, key) && shallow(a[key], b[key])
|
|
3345
|
+
);
|
|
3346
|
+
}
|
|
3347
|
+
|
|
3348
|
+
// src/lib/SortedList.ts
|
|
3349
|
+
function bisectRight(arr, x, lt) {
|
|
3350
|
+
let lo = 0;
|
|
3351
|
+
let hi = arr.length;
|
|
3352
|
+
while (lo < hi) {
|
|
3353
|
+
const mid = lo + (hi - lo >> 1);
|
|
3354
|
+
if (lt(x, arr[mid])) {
|
|
3355
|
+
hi = mid;
|
|
3356
|
+
} else {
|
|
3357
|
+
lo = mid + 1;
|
|
3358
|
+
}
|
|
3359
|
+
}
|
|
3360
|
+
return lo;
|
|
3361
|
+
}
|
|
3362
|
+
var SortedList = class _SortedList {
|
|
3363
|
+
#data;
|
|
3364
|
+
#lt;
|
|
3365
|
+
constructor(alreadySortedList, lt) {
|
|
3366
|
+
this.#lt = lt;
|
|
3367
|
+
this.#data = alreadySortedList;
|
|
3368
|
+
}
|
|
3369
|
+
static with(lt) {
|
|
3370
|
+
return _SortedList.fromAlreadySorted([], lt);
|
|
3371
|
+
}
|
|
3372
|
+
static from(arr, lt) {
|
|
3373
|
+
const sorted = new _SortedList([], lt);
|
|
3374
|
+
for (const item of arr) {
|
|
3375
|
+
sorted.add(item);
|
|
3376
|
+
}
|
|
3377
|
+
return sorted;
|
|
3378
|
+
}
|
|
3379
|
+
static fromAlreadySorted(alreadySorted, lt) {
|
|
3380
|
+
return new _SortedList(alreadySorted, lt);
|
|
3381
|
+
}
|
|
3382
|
+
/**
|
|
3383
|
+
* Clones the sorted list to a new instance.
|
|
3384
|
+
*/
|
|
3385
|
+
clone() {
|
|
3386
|
+
return new _SortedList(this.#data.slice(), this.#lt);
|
|
3387
|
+
}
|
|
3388
|
+
/**
|
|
3389
|
+
* Adds a new item to the sorted list, such that it remains sorted.
|
|
3390
|
+
*/
|
|
3391
|
+
add(value) {
|
|
3392
|
+
const idx = bisectRight(this.#data, value, this.#lt);
|
|
3393
|
+
this.#data.splice(idx, 0, value);
|
|
3394
|
+
}
|
|
3395
|
+
/**
|
|
3396
|
+
* Removes all values from the sorted list, making it empty again.
|
|
3397
|
+
* Returns whether the list was mutated or not.
|
|
3398
|
+
*/
|
|
3399
|
+
clear() {
|
|
3400
|
+
const hadData = this.#data.length > 0;
|
|
3401
|
+
this.#data.length = 0;
|
|
3402
|
+
return hadData;
|
|
3403
|
+
}
|
|
3404
|
+
/**
|
|
3405
|
+
* Removes the first value matching the predicate.
|
|
3406
|
+
* Returns whether the list was mutated or not.
|
|
3407
|
+
*/
|
|
3408
|
+
removeBy(predicate, limit = Number.POSITIVE_INFINITY) {
|
|
3409
|
+
let deleted = 0;
|
|
3410
|
+
for (let i = 0; i < this.#data.length; i++) {
|
|
3411
|
+
if (predicate(this.#data[i])) {
|
|
3412
|
+
this.#data.splice(i, 1);
|
|
3413
|
+
deleted++;
|
|
3414
|
+
if (deleted >= limit) {
|
|
3415
|
+
break;
|
|
3416
|
+
} else {
|
|
3417
|
+
i--;
|
|
3418
|
+
}
|
|
3419
|
+
}
|
|
3420
|
+
}
|
|
3421
|
+
return deleted > 0;
|
|
3422
|
+
}
|
|
3423
|
+
/**
|
|
3424
|
+
* Removes the given value from the sorted list, if it exists. The given
|
|
3425
|
+
* value must be `===` to one of the list items. Only the first entry will be
|
|
3426
|
+
* removed if the element exists in the sorted list multiple times.
|
|
3427
|
+
*
|
|
3428
|
+
* Returns whether the list was mutated or not.
|
|
3429
|
+
*/
|
|
3430
|
+
remove(value) {
|
|
3431
|
+
const idx = this.#data.indexOf(value);
|
|
3432
|
+
if (idx >= 0) {
|
|
3433
|
+
this.#data.splice(idx, 1);
|
|
3434
|
+
return true;
|
|
3435
|
+
}
|
|
3436
|
+
return false;
|
|
3437
|
+
}
|
|
3438
|
+
at(index) {
|
|
3439
|
+
return this.#data[index];
|
|
3440
|
+
}
|
|
3441
|
+
get length() {
|
|
3442
|
+
return this.#data.length;
|
|
3443
|
+
}
|
|
3444
|
+
*filter(predicate) {
|
|
3445
|
+
for (const item of this.#data) {
|
|
3446
|
+
if (predicate(item)) {
|
|
3447
|
+
yield item;
|
|
3448
|
+
}
|
|
3449
|
+
}
|
|
3450
|
+
}
|
|
3451
|
+
// XXXX If we keep this, add unit tests. Or remove it.
|
|
3452
|
+
*findAllRight(predicate) {
|
|
3453
|
+
for (let i = this.#data.length - 1; i >= 0; i--) {
|
|
3454
|
+
const item = this.#data[i];
|
|
3455
|
+
if (predicate(item, i)) {
|
|
3456
|
+
yield item;
|
|
3457
|
+
}
|
|
3458
|
+
}
|
|
3459
|
+
}
|
|
3460
|
+
[Symbol.iterator]() {
|
|
3461
|
+
return this.#data[Symbol.iterator]();
|
|
3462
|
+
}
|
|
3463
|
+
*iterReversed() {
|
|
3464
|
+
for (let i = this.#data.length - 1; i >= 0; i--) {
|
|
3465
|
+
yield this.#data[i];
|
|
3466
|
+
}
|
|
3467
|
+
}
|
|
3468
|
+
/** Finds the leftmost item that matches the predicate. */
|
|
3469
|
+
find(predicate, start) {
|
|
3470
|
+
const idx = this.findIndex(predicate, start);
|
|
3471
|
+
return idx > -1 ? this.#data.at(idx) : void 0;
|
|
3472
|
+
}
|
|
3473
|
+
/** Finds the leftmost index that matches the predicate. */
|
|
3474
|
+
findIndex(predicate, start = 0) {
|
|
3475
|
+
for (let i = Math.max(0, start); i < this.#data.length; i++) {
|
|
3476
|
+
if (predicate(this.#data[i], i)) {
|
|
3477
|
+
return i;
|
|
3478
|
+
}
|
|
3479
|
+
}
|
|
3480
|
+
return -1;
|
|
3481
|
+
}
|
|
3482
|
+
/** Finds the rightmost item that matches the predicate. */
|
|
3483
|
+
findRight(predicate, start) {
|
|
3484
|
+
const idx = this.findIndexRight(predicate, start);
|
|
3485
|
+
return idx > -1 ? this.#data.at(idx) : void 0;
|
|
3486
|
+
}
|
|
3487
|
+
/** Finds the rightmost index that matches the predicate. */
|
|
3488
|
+
findIndexRight(predicate, start = this.#data.length - 1) {
|
|
3489
|
+
for (let i = Math.min(start, this.#data.length - 1); i >= 0; i--) {
|
|
3490
|
+
if (predicate(this.#data[i], i)) {
|
|
3491
|
+
return i;
|
|
3492
|
+
}
|
|
3493
|
+
}
|
|
3494
|
+
return -1;
|
|
3495
|
+
}
|
|
3496
|
+
get rawArray() {
|
|
3497
|
+
return this.#data;
|
|
3498
|
+
}
|
|
3499
|
+
};
|
|
3500
|
+
|
|
3501
|
+
// src/lib/TreePool.ts
|
|
3502
|
+
var TreePool = class {
|
|
3503
|
+
#_items;
|
|
3504
|
+
#_childrenOf;
|
|
3505
|
+
#_sorted;
|
|
3506
|
+
#_primaryKey;
|
|
3507
|
+
#_parentKeyFn;
|
|
3508
|
+
#_lt;
|
|
3509
|
+
constructor(primaryKey, parentKey, lt) {
|
|
3510
|
+
this.#_primaryKey = primaryKey;
|
|
3511
|
+
this.#_parentKeyFn = parentKey;
|
|
3512
|
+
this.#_lt = lt;
|
|
3513
|
+
this.#_items = /* @__PURE__ */ new Map();
|
|
3514
|
+
this.#_childrenOf = new DefaultMap(() => /* @__PURE__ */ new Set());
|
|
3515
|
+
this.#_sorted = SortedList.with(lt);
|
|
3516
|
+
}
|
|
3517
|
+
get(id) {
|
|
3518
|
+
return this.#_items.get(id);
|
|
3519
|
+
}
|
|
3520
|
+
getOrThrow(id) {
|
|
3521
|
+
return this.get(id) ?? raise(`Item with id ${id} not found`);
|
|
3522
|
+
}
|
|
3523
|
+
get sorted() {
|
|
3524
|
+
return this.#_sorted;
|
|
3525
|
+
}
|
|
3526
|
+
getParentId(id) {
|
|
3527
|
+
const item = this.getOrThrow(id);
|
|
3528
|
+
return this.#_parentKeyFn(item);
|
|
3529
|
+
}
|
|
3530
|
+
getParent(id) {
|
|
3531
|
+
const parentId = this.getParentId(id);
|
|
3532
|
+
return parentId ? this.getOrThrow(parentId) : null;
|
|
3533
|
+
}
|
|
3534
|
+
getChildren(id) {
|
|
3535
|
+
const childIds = this.#_childrenOf.get(id);
|
|
3536
|
+
if (!childIds) return [];
|
|
3537
|
+
return Array.from(childIds).map(
|
|
3538
|
+
(id2) => this.#_items.get(id2)
|
|
3539
|
+
// eslint-disable-line no-restricted-syntax
|
|
3540
|
+
);
|
|
3541
|
+
}
|
|
3542
|
+
*walkUp(id, predicate) {
|
|
3543
|
+
const includeSelf = true;
|
|
3544
|
+
let nodeId = id;
|
|
3545
|
+
do {
|
|
3546
|
+
const item = this.getOrThrow(nodeId);
|
|
3547
|
+
if (includeSelf || nodeId !== id) {
|
|
3548
|
+
if (!predicate || predicate(item)) {
|
|
3549
|
+
yield item;
|
|
3550
|
+
}
|
|
3551
|
+
}
|
|
3552
|
+
nodeId = this.#_parentKeyFn(item);
|
|
3553
|
+
} while (nodeId !== null);
|
|
3554
|
+
}
|
|
3555
|
+
// XXXX Generalize
|
|
3556
|
+
*walkLeft(id, predicate) {
|
|
3557
|
+
const self = this.getOrThrow(id);
|
|
3558
|
+
const siblings = SortedList.from(this.getSiblings(id), this.#_lt);
|
|
3559
|
+
for (const sibling of siblings.iterReversed()) {
|
|
3560
|
+
if (this.#_lt(self, sibling)) continue;
|
|
3561
|
+
if (!predicate || predicate(sibling)) {
|
|
3562
|
+
yield sibling;
|
|
3563
|
+
}
|
|
3564
|
+
}
|
|
3565
|
+
}
|
|
3566
|
+
// XXXX Generalize
|
|
3567
|
+
*walkRight(id, predicate) {
|
|
3568
|
+
const self = this.getOrThrow(id);
|
|
3569
|
+
const siblings = SortedList.from(this.getSiblings(id), this.#_lt);
|
|
3570
|
+
for (const sibling of siblings) {
|
|
3571
|
+
if (this.#_lt(sibling, self)) continue;
|
|
3572
|
+
if (!predicate || predicate(sibling)) {
|
|
3573
|
+
yield sibling;
|
|
3574
|
+
}
|
|
3575
|
+
}
|
|
3576
|
+
}
|
|
3577
|
+
// XXXX Generalize
|
|
3578
|
+
*walkDown(id, predicate) {
|
|
3579
|
+
const children = SortedList.from(this.getChildren(id), this.#_lt).rawArray;
|
|
3580
|
+
for (let i = children.length - 1; i >= 0; i--) {
|
|
3581
|
+
const child = children[i];
|
|
3582
|
+
yield* this.walkDown(
|
|
3583
|
+
this.#_primaryKey(child),
|
|
3584
|
+
predicate
|
|
3585
|
+
// "depth-first",
|
|
3586
|
+
// true
|
|
3587
|
+
);
|
|
3588
|
+
if (!predicate || predicate(child)) {
|
|
3589
|
+
yield child;
|
|
3590
|
+
}
|
|
3591
|
+
}
|
|
3592
|
+
}
|
|
3593
|
+
/** Returns all siblings, not including the item itself. */
|
|
3594
|
+
getSiblings(id) {
|
|
3595
|
+
const self = this.getOrThrow(id);
|
|
3596
|
+
const parentId = this.getParentId(id);
|
|
3597
|
+
return this.getChildren(parentId).filter((item) => item !== self);
|
|
3598
|
+
}
|
|
3599
|
+
[Symbol.iterator]() {
|
|
3600
|
+
return this.#_sorted[Symbol.iterator]();
|
|
3601
|
+
}
|
|
3602
|
+
upsert(item) {
|
|
3603
|
+
const pk = this.#_primaryKey(item);
|
|
3604
|
+
const existing = this.#_items.get(pk);
|
|
3605
|
+
if (existing) {
|
|
3606
|
+
if (this.#_parentKeyFn(existing) !== this.#_parentKeyFn(item)) {
|
|
3607
|
+
throw new Error(
|
|
3608
|
+
"Cannot upsert parent ID changes that change the tree structure. Remove the entry first, and recreate it"
|
|
3609
|
+
);
|
|
3610
|
+
}
|
|
3611
|
+
this.#_sorted.remove(existing);
|
|
3612
|
+
}
|
|
3613
|
+
this.#_items.set(pk, item);
|
|
3614
|
+
this.#_sorted.add(item);
|
|
3615
|
+
const parentId = this.#_parentKeyFn(item);
|
|
3616
|
+
this.#_childrenOf.getOrCreate(parentId).add(pk);
|
|
3617
|
+
}
|
|
3618
|
+
remove(pk) {
|
|
3619
|
+
const item = this.#_items.get(pk);
|
|
3620
|
+
if (!item) return false;
|
|
3621
|
+
const childIds = this.#_childrenOf.get(pk);
|
|
3622
|
+
if (childIds) {
|
|
3623
|
+
throw new Error(
|
|
3624
|
+
`Cannot remove item '${pk}' while it still has children. Remove children first.`
|
|
3625
|
+
);
|
|
3626
|
+
}
|
|
3627
|
+
const parentId = this.#_parentKeyFn(item);
|
|
3628
|
+
const siblings = this.#_childrenOf.get(parentId);
|
|
3629
|
+
if (siblings) {
|
|
3630
|
+
siblings.delete(pk);
|
|
3631
|
+
if (siblings.size === 0) {
|
|
3632
|
+
this.#_childrenOf.delete(parentId);
|
|
3633
|
+
}
|
|
3634
|
+
}
|
|
3635
|
+
this.#_sorted.remove(item);
|
|
3636
|
+
this.#_childrenOf.delete(pk);
|
|
3637
|
+
this.#_items.delete(pk);
|
|
3638
|
+
return true;
|
|
3639
|
+
}
|
|
3640
|
+
clear() {
|
|
3641
|
+
if (this.#_items.size === 0) return false;
|
|
3642
|
+
this.#_childrenOf.clear();
|
|
3643
|
+
this.#_items.clear();
|
|
3644
|
+
this.#_sorted.clear();
|
|
3645
|
+
return true;
|
|
3646
|
+
}
|
|
3647
|
+
};
|
|
3648
|
+
|
|
3649
|
+
// src/protocol/AuthToken.ts
|
|
3650
|
+
var Permission = /* @__PURE__ */ ((Permission2) => {
|
|
3651
|
+
Permission2["Read"] = "room:read";
|
|
3652
|
+
Permission2["Write"] = "room:write";
|
|
3653
|
+
Permission2["PresenceWrite"] = "room:presence:write";
|
|
3654
|
+
Permission2["CommentsWrite"] = "comments:write";
|
|
3655
|
+
Permission2["CommentsRead"] = "comments:read";
|
|
3656
|
+
return Permission2;
|
|
3657
|
+
})(Permission || {});
|
|
3658
|
+
function canWriteStorage(scopes) {
|
|
3659
|
+
return scopes.includes("room:write" /* Write */);
|
|
3660
|
+
}
|
|
3661
|
+
function canComment(scopes) {
|
|
3662
|
+
return scopes.includes("comments:write" /* CommentsWrite */) || scopes.includes("room:write" /* Write */);
|
|
3663
|
+
}
|
|
3664
|
+
function isValidAuthTokenPayload(data) {
|
|
3665
|
+
return isPlainObject(data) && (data.k === "acc" /* ACCESS_TOKEN */ || data.k === "id" /* ID_TOKEN */ || data.k === "sec-legacy" /* SECRET_LEGACY */);
|
|
3666
|
+
}
|
|
3667
|
+
function parseAuthToken(rawTokenString) {
|
|
3668
|
+
const tokenParts = rawTokenString.split(".");
|
|
3669
|
+
if (tokenParts.length !== 3) {
|
|
3670
|
+
throw new Error("Authentication error: invalid JWT token");
|
|
3671
|
+
}
|
|
3672
|
+
const payload = tryParseJson(b64decode(tokenParts[1]));
|
|
3673
|
+
if (!(payload && isValidAuthTokenPayload(payload))) {
|
|
3674
|
+
throw new Error(
|
|
3675
|
+
"Authentication error: expected a valid token but did not get one. Hint: if you are using a callback, ensure the room is passed when creating the token. For more information: https://liveblocks.io/docs/api-reference/liveblocks-client#createClientCallback"
|
|
3676
|
+
);
|
|
3677
|
+
}
|
|
3678
|
+
return {
|
|
3679
|
+
raw: rawTokenString,
|
|
3680
|
+
parsed: payload
|
|
3681
|
+
};
|
|
3682
|
+
}
|
|
3683
|
+
|
|
3684
|
+
// src/types/ai.ts
|
|
3685
|
+
function appendDelta(content, delta) {
|
|
3686
|
+
const lastPart = content[content.length - 1];
|
|
3687
|
+
switch (delta.type) {
|
|
3688
|
+
case "reasoning":
|
|
3689
|
+
case "text":
|
|
3690
|
+
case "tool-call":
|
|
3691
|
+
content.push(delta);
|
|
3692
|
+
break;
|
|
3693
|
+
case "text-delta":
|
|
3694
|
+
if (lastPart?.type === "text") {
|
|
3695
|
+
lastPart.text += delta.textDelta;
|
|
3696
|
+
} else {
|
|
3697
|
+
content.push({ type: "text", text: delta.textDelta });
|
|
3698
|
+
}
|
|
3699
|
+
break;
|
|
3700
|
+
case "reasoning-delta":
|
|
3701
|
+
if (lastPart?.type === "reasoning") {
|
|
3702
|
+
lastPart.text += delta.textDelta;
|
|
3703
|
+
lastPart.signature ??= delta.signature;
|
|
3704
|
+
} else {
|
|
3705
|
+
content.push({
|
|
3706
|
+
type: "reasoning",
|
|
3707
|
+
text: delta.textDelta ?? "",
|
|
3708
|
+
signature: delta.signature
|
|
3709
|
+
});
|
|
3710
|
+
}
|
|
3711
|
+
break;
|
|
3712
|
+
default:
|
|
3713
|
+
return assertNever(delta, "Unhandled case");
|
|
3714
|
+
}
|
|
3715
|
+
}
|
|
3716
|
+
|
|
3717
|
+
// src/ai.ts
|
|
3718
|
+
var DEFAULT_REQUEST_TIMEOUT = 4e3;
|
|
3719
|
+
var DEFAULT_AI_TIMEOUT = 3e4;
|
|
3720
|
+
function now() {
|
|
3721
|
+
return (/* @__PURE__ */ new Date()).toISOString();
|
|
3722
|
+
}
|
|
3723
|
+
function createStore_forTools() {
|
|
3724
|
+
const toolsByChatId\u03A3 = new DefaultMap((_chatId) => {
|
|
3725
|
+
return new DefaultMap((_toolName) => {
|
|
3726
|
+
return new Signal(void 0);
|
|
3727
|
+
});
|
|
3728
|
+
});
|
|
3729
|
+
function getToolDefinition\u03A3(chatId, toolName) {
|
|
3730
|
+
return toolsByChatId\u03A3.getOrCreate(chatId).getOrCreate(toolName);
|
|
3731
|
+
}
|
|
3732
|
+
function addToolDefinition(chatId, name, definition) {
|
|
3733
|
+
toolsByChatId\u03A3.getOrCreate(chatId).getOrCreate(name).set(definition);
|
|
3734
|
+
}
|
|
3735
|
+
function removeToolDefinition(chatId, toolName) {
|
|
3736
|
+
const tools = toolsByChatId\u03A3.get(chatId);
|
|
3737
|
+
if (tools === void 0) return;
|
|
3738
|
+
const tool = tools.get(toolName);
|
|
3739
|
+
if (tool === void 0) return;
|
|
3740
|
+
tool.set(void 0);
|
|
3741
|
+
}
|
|
3742
|
+
function getToolsForChat(chatId) {
|
|
3743
|
+
const tools = toolsByChatId\u03A3.get(chatId);
|
|
3744
|
+
if (tools === void 0) return [];
|
|
3745
|
+
return Array.from(tools.entries()).map(([name, tool]) => {
|
|
3746
|
+
if (tool.get() === void 0) return null;
|
|
3747
|
+
return {
|
|
3748
|
+
name,
|
|
3749
|
+
definition: tool.get()
|
|
3750
|
+
};
|
|
3751
|
+
}).filter((tool) => tool !== null);
|
|
3752
|
+
}
|
|
3753
|
+
return {
|
|
3754
|
+
getToolCallByName\u03A3: getToolDefinition\u03A3,
|
|
3755
|
+
getToolsForChat,
|
|
3756
|
+
addToolDefinition,
|
|
3757
|
+
removeToolDefinition
|
|
3758
|
+
};
|
|
3759
|
+
}
|
|
3760
|
+
function createStore_forChatMessages() {
|
|
3761
|
+
const messagePoolByChatId\u03A3 = new DefaultMap(
|
|
3762
|
+
(_chatId) => new MutableSignal(
|
|
3763
|
+
new TreePool(
|
|
3764
|
+
(x) => x.id,
|
|
3765
|
+
(x) => x.parentId,
|
|
3766
|
+
(x, y) => x.createdAt < y.createdAt
|
|
3767
|
+
)
|
|
3768
|
+
)
|
|
3769
|
+
);
|
|
3770
|
+
const pendingMessages\u03A3 = new MutableSignal(
|
|
3771
|
+
/* @__PURE__ */ new Map()
|
|
3772
|
+
);
|
|
3773
|
+
function createOptimistically(chatId, role, parentId, third) {
|
|
3774
|
+
const id = `ms_${nanoid()}`;
|
|
3775
|
+
const createdAt = now();
|
|
3776
|
+
if (role === "user") {
|
|
3777
|
+
const content = third;
|
|
3778
|
+
upsert({
|
|
3779
|
+
id,
|
|
3780
|
+
chatId,
|
|
3781
|
+
role,
|
|
3782
|
+
parentId,
|
|
3783
|
+
createdAt,
|
|
3784
|
+
content
|
|
3785
|
+
});
|
|
3786
|
+
} else {
|
|
3787
|
+
upsert({
|
|
3788
|
+
id,
|
|
3789
|
+
chatId,
|
|
3790
|
+
role,
|
|
3791
|
+
parentId,
|
|
3792
|
+
createdAt,
|
|
3793
|
+
status: "pending",
|
|
3794
|
+
contentSoFar: []
|
|
3795
|
+
});
|
|
3796
|
+
}
|
|
3797
|
+
return id;
|
|
3798
|
+
}
|
|
3799
|
+
function upsertMany(messages) {
|
|
3800
|
+
batch(() => {
|
|
3801
|
+
for (const message of messages) {
|
|
3802
|
+
upsert(message);
|
|
3803
|
+
}
|
|
3804
|
+
});
|
|
3805
|
+
}
|
|
3806
|
+
function remove(chatId, messageId) {
|
|
3807
|
+
const chatMsgs\u03A3 = messagePoolByChatId\u03A3.get(chatId);
|
|
3808
|
+
if (!chatMsgs\u03A3) return;
|
|
3809
|
+
const existing = chatMsgs\u03A3.get().get(messageId);
|
|
3810
|
+
if (!existing || existing.deletedAt) return;
|
|
3811
|
+
if (existing.role === "assistant" && (existing.status === "pending" || existing.status === "failed")) {
|
|
3812
|
+
upsert({ ...existing, deletedAt: now(), contentSoFar: [] });
|
|
3813
|
+
} else {
|
|
3814
|
+
upsert({ ...existing, deletedAt: now(), content: [] });
|
|
3815
|
+
}
|
|
3816
|
+
}
|
|
3817
|
+
function removeByChatId(chatId) {
|
|
3818
|
+
const chatMsgs\u03A3 = messagePoolByChatId\u03A3.get(chatId);
|
|
3819
|
+
if (chatMsgs\u03A3 === void 0) return;
|
|
3820
|
+
chatMsgs\u03A3.mutate((pool) => pool.clear());
|
|
3821
|
+
}
|
|
3822
|
+
function upsert(message) {
|
|
3823
|
+
batch(() => {
|
|
3824
|
+
const chatMsgs\u03A3 = messagePoolByChatId\u03A3.getOrCreate(message.chatId);
|
|
3825
|
+
chatMsgs\u03A3.mutate((pool) => pool.upsert(message));
|
|
3826
|
+
if (message.role === "assistant" && message.status === "pending") {
|
|
3827
|
+
pendingMessages\u03A3.mutate((lut) => {
|
|
3828
|
+
lut.set(message.id, structuredClone(message));
|
|
3829
|
+
});
|
|
3830
|
+
} else {
|
|
3831
|
+
pendingMessages\u03A3.mutate((lut) => {
|
|
3832
|
+
lut.delete(message.id);
|
|
3833
|
+
});
|
|
3834
|
+
}
|
|
3835
|
+
});
|
|
3836
|
+
}
|
|
3837
|
+
function addDelta(messageId, delta) {
|
|
3838
|
+
pendingMessages\u03A3.mutate((lut) => {
|
|
3839
|
+
const message = lut.get(messageId);
|
|
3840
|
+
if (message === void 0) return false;
|
|
3841
|
+
appendDelta(message.contentSoFar, delta);
|
|
3842
|
+
lut.set(messageId, message);
|
|
3843
|
+
return true;
|
|
3844
|
+
});
|
|
3845
|
+
}
|
|
3846
|
+
function* iterPendingMessages() {
|
|
3847
|
+
for (const chatMsgs\u03A3 of messagePoolByChatId\u03A3.values()) {
|
|
3848
|
+
for (const m of chatMsgs\u03A3.get()) {
|
|
3849
|
+
if (m.role === "assistant" && m.status === "pending") {
|
|
3850
|
+
yield m;
|
|
3851
|
+
}
|
|
3852
|
+
}
|
|
3853
|
+
}
|
|
3854
|
+
}
|
|
3855
|
+
function failAllPending() {
|
|
3856
|
+
batch(() => {
|
|
3857
|
+
pendingMessages\u03A3.mutate((lut) => lut.clear());
|
|
3858
|
+
upsertMany(
|
|
3859
|
+
Array.from(iterPendingMessages()).map(
|
|
3860
|
+
(message) => ({
|
|
3861
|
+
...message,
|
|
3862
|
+
status: "failed",
|
|
3863
|
+
errorReason: "Lost connection"
|
|
3864
|
+
})
|
|
3865
|
+
)
|
|
3866
|
+
);
|
|
3867
|
+
});
|
|
3868
|
+
}
|
|
3869
|
+
function getMessageById(messageId) {
|
|
3870
|
+
for (const messages\u03A3 of messagePoolByChatId\u03A3.values()) {
|
|
3871
|
+
const message = messages\u03A3.get().get(messageId);
|
|
3872
|
+
if (message) {
|
|
3873
|
+
return message;
|
|
3874
|
+
}
|
|
3875
|
+
}
|
|
3876
|
+
return void 0;
|
|
3877
|
+
}
|
|
3878
|
+
function first(iterable) {
|
|
3879
|
+
const result = iterable.next();
|
|
3880
|
+
return result.done ? void 0 : result.value;
|
|
3881
|
+
}
|
|
3882
|
+
function selectBranch(pool, preferredBranch) {
|
|
3883
|
+
function isAlive(message2) {
|
|
3884
|
+
if (!message2.deletedAt) {
|
|
3885
|
+
return true;
|
|
3886
|
+
}
|
|
3887
|
+
for (const _ of pool.walkDown(message2.id, (m) => !m.deletedAt)) {
|
|
3888
|
+
return true;
|
|
3889
|
+
}
|
|
3890
|
+
return false;
|
|
3891
|
+
}
|
|
3892
|
+
function selectSpine(leaf) {
|
|
3893
|
+
const spine = [];
|
|
3894
|
+
for (const message2 of pool.walkUp(leaf.id)) {
|
|
3895
|
+
const prev = first(pool.walkLeft(message2.id, isAlive))?.id ?? null;
|
|
3896
|
+
const next = first(pool.walkRight(message2.id, isAlive))?.id ?? null;
|
|
3897
|
+
if (!message2.deletedAt || prev || next) {
|
|
3898
|
+
spine.push({ ...message2, prev, next });
|
|
3899
|
+
}
|
|
3900
|
+
}
|
|
3901
|
+
return spine.reverse();
|
|
3902
|
+
}
|
|
3903
|
+
function fallback() {
|
|
3904
|
+
const latest = pool.sorted.findRight((m) => !m.deletedAt);
|
|
3905
|
+
return latest ? selectSpine(latest) : [];
|
|
3906
|
+
}
|
|
3907
|
+
if (preferredBranch === null) {
|
|
3908
|
+
return fallback();
|
|
3909
|
+
}
|
|
3910
|
+
const message = pool.get(preferredBranch);
|
|
3911
|
+
if (!message) {
|
|
3912
|
+
return fallback();
|
|
3913
|
+
}
|
|
3914
|
+
for (const current of pool.walkUp(message.id)) {
|
|
3915
|
+
for (const desc of pool.walkDown(current.id, (m) => !m.deletedAt)) {
|
|
3916
|
+
return selectSpine(desc);
|
|
3917
|
+
}
|
|
3918
|
+
if (!current.deletedAt) {
|
|
3919
|
+
return selectSpine(current);
|
|
3920
|
+
}
|
|
3921
|
+
}
|
|
3922
|
+
return fallback();
|
|
3923
|
+
}
|
|
3924
|
+
function getLatestUserMessageAncestor(chatId, messageId) {
|
|
3925
|
+
const pool = messagePoolByChatId\u03A3.getOrCreate(chatId).get();
|
|
3926
|
+
const message = pool.get(messageId);
|
|
3927
|
+
if (!message) return null;
|
|
3928
|
+
if (message.role === "user") return message.id;
|
|
3929
|
+
for (const m of pool.walkUp(message.id)) {
|
|
3930
|
+
if (m.role === "user" && !m.deletedAt) {
|
|
3931
|
+
return m.id;
|
|
3932
|
+
}
|
|
3933
|
+
}
|
|
3934
|
+
return null;
|
|
3935
|
+
}
|
|
3936
|
+
const immutableMessagesByBranch = new DefaultMap((chatId) => {
|
|
3937
|
+
return new DefaultMap((branchId) => {
|
|
3938
|
+
const messages\u03A3 = DerivedSignal.from(() => {
|
|
3939
|
+
const pool = messagePoolByChatId\u03A3.getOrCreate(chatId).get();
|
|
3940
|
+
return selectBranch(pool, branchId);
|
|
3941
|
+
}, shallow2);
|
|
3942
|
+
return DerivedSignal.from(() => {
|
|
3943
|
+
const pendingMessages = pendingMessages\u03A3.get();
|
|
3944
|
+
return messages\u03A3.get().map((message) => {
|
|
3945
|
+
if (message.role !== "assistant" || message.status !== "pending") {
|
|
3946
|
+
return message;
|
|
3947
|
+
}
|
|
3948
|
+
const pendingMessage = pendingMessages.get(message.id);
|
|
3949
|
+
if (pendingMessage === void 0) return message;
|
|
3950
|
+
return {
|
|
3951
|
+
...message,
|
|
3952
|
+
contentSoFar: pendingMessage.contentSoFar
|
|
3953
|
+
};
|
|
3954
|
+
});
|
|
3955
|
+
}, shallow);
|
|
3956
|
+
});
|
|
3957
|
+
});
|
|
3958
|
+
function getChatMessagesForBranch\u03A3(chatId, branch) {
|
|
3959
|
+
return immutableMessagesByBranch.getOrCreate(chatId).getOrCreate(branch || null);
|
|
3960
|
+
}
|
|
3961
|
+
const messagesByChatId\u03A3 = new DefaultMap((chatId) => {
|
|
3962
|
+
return DerivedSignal.from(() => {
|
|
3963
|
+
const pool = messagePoolByChatId\u03A3.getOrCreate(chatId).get();
|
|
3964
|
+
return Array.from(pool.sorted);
|
|
3965
|
+
});
|
|
3966
|
+
});
|
|
3967
|
+
function getMessagesForChat\u03A3(chatId) {
|
|
3968
|
+
return messagesByChatId\u03A3.getOrCreate(chatId);
|
|
3969
|
+
}
|
|
3970
|
+
return {
|
|
3971
|
+
// Readers
|
|
3972
|
+
getMessageById,
|
|
3973
|
+
getChatMessagesForBranch\u03A3,
|
|
3974
|
+
getMessagesForChat\u03A3,
|
|
3975
|
+
getLatestUserMessageAncestor,
|
|
3976
|
+
// Mutations
|
|
3977
|
+
createOptimistically,
|
|
3978
|
+
upsert,
|
|
3979
|
+
upsertMany,
|
|
3980
|
+
remove,
|
|
3981
|
+
removeByChatId,
|
|
3982
|
+
addDelta,
|
|
3983
|
+
failAllPending
|
|
3984
|
+
};
|
|
3985
|
+
}
|
|
3986
|
+
function createStore_forUserAiChats() {
|
|
3987
|
+
const mutable\u03A3 = new MutableSignal(
|
|
3988
|
+
SortedList.with((x, y) => y.createdAt < x.createdAt)
|
|
3989
|
+
);
|
|
3990
|
+
const chats\u03A3 = DerivedSignal.from(
|
|
3991
|
+
() => Array.from(mutable\u03A3.get()).filter((c) => !c.ephemeral && !c.deletedAt)
|
|
3992
|
+
);
|
|
3993
|
+
function upsertMany(chats) {
|
|
3994
|
+
mutable\u03A3.mutate((list) => {
|
|
3995
|
+
for (const chat of chats) {
|
|
3996
|
+
remove(chat.id);
|
|
3997
|
+
list.add(chat);
|
|
3998
|
+
}
|
|
3999
|
+
});
|
|
4000
|
+
}
|
|
4001
|
+
function upsert(chat) {
|
|
4002
|
+
upsertMany([chat]);
|
|
4003
|
+
}
|
|
4004
|
+
function remove(chatId) {
|
|
4005
|
+
mutable\u03A3.mutate((list) => list.removeBy((c) => c.id === chatId, 1));
|
|
4006
|
+
}
|
|
4007
|
+
return {
|
|
4008
|
+
chats\u03A3,
|
|
4009
|
+
// Mutations
|
|
4010
|
+
upsert,
|
|
4011
|
+
upsertMany,
|
|
4012
|
+
remove
|
|
4013
|
+
};
|
|
4014
|
+
}
|
|
4015
|
+
function createAi(config) {
|
|
4016
|
+
const managedSocket = new ManagedSocket(
|
|
4017
|
+
config.delegates,
|
|
4018
|
+
config.enableDebugLogging,
|
|
4019
|
+
false
|
|
4020
|
+
// AI doesn't have actors (yet, but it will)
|
|
4021
|
+
);
|
|
4022
|
+
const clientId = nanoid(7);
|
|
4023
|
+
const chatsStore = createStore_forUserAiChats();
|
|
4024
|
+
const messagesStore = createStore_forChatMessages();
|
|
4025
|
+
const toolsStore = createStore_forTools();
|
|
4026
|
+
const context = {
|
|
4027
|
+
staticSessionInfoSig: new Signal(null),
|
|
4028
|
+
dynamicSessionInfoSig: new Signal(null),
|
|
4029
|
+
pendingCmds: /* @__PURE__ */ new Map(),
|
|
4030
|
+
chatsStore,
|
|
4031
|
+
messagesStore,
|
|
4032
|
+
toolsStore,
|
|
4033
|
+
contextByChatId: /* @__PURE__ */ new Map()
|
|
4034
|
+
};
|
|
4035
|
+
let lastTokenKey;
|
|
4036
|
+
function onStatusDidChange(newStatus) {
|
|
4037
|
+
warn("onStatusDidChange", newStatus);
|
|
4038
|
+
const authValue = managedSocket.authValue;
|
|
4039
|
+
if (authValue !== null) {
|
|
4040
|
+
const tokenKey = getBearerTokenFromAuthValue(authValue);
|
|
4041
|
+
if (tokenKey !== lastTokenKey) {
|
|
4042
|
+
lastTokenKey = tokenKey;
|
|
4043
|
+
if (authValue.type === "secret") {
|
|
4044
|
+
const token = authValue.token.parsed;
|
|
4045
|
+
context.staticSessionInfoSig.set({
|
|
4046
|
+
userId: token.k === "sec-legacy" /* SECRET_LEGACY */ ? token.id : token.uid,
|
|
4047
|
+
userInfo: token.k === "sec-legacy" /* SECRET_LEGACY */ ? token.info : token.ui
|
|
4048
|
+
});
|
|
4049
|
+
} else {
|
|
4050
|
+
context.staticSessionInfoSig.set({
|
|
4051
|
+
userId: void 0,
|
|
4052
|
+
userInfo: void 0
|
|
4053
|
+
});
|
|
4054
|
+
}
|
|
4055
|
+
}
|
|
4056
|
+
}
|
|
4057
|
+
}
|
|
4058
|
+
let _connectionLossTimerId;
|
|
4059
|
+
let _hasLostConnection = false;
|
|
4060
|
+
function handleConnectionLossEvent(newStatus) {
|
|
4061
|
+
if (newStatus === "reconnecting") {
|
|
4062
|
+
_connectionLossTimerId = setTimeout(() => {
|
|
4063
|
+
_hasLostConnection = true;
|
|
4064
|
+
}, config.lostConnectionTimeout);
|
|
4065
|
+
} else {
|
|
4066
|
+
clearTimeout(_connectionLossTimerId);
|
|
4067
|
+
if (_hasLostConnection) {
|
|
4068
|
+
_hasLostConnection = false;
|
|
4069
|
+
}
|
|
4070
|
+
}
|
|
4071
|
+
}
|
|
4072
|
+
function onDidConnect() {
|
|
4073
|
+
warn("onDidConnect");
|
|
4074
|
+
}
|
|
4075
|
+
function onDidDisconnect() {
|
|
4076
|
+
warn("onDidDisconnect");
|
|
4077
|
+
}
|
|
4078
|
+
function handleServerMessage(event) {
|
|
4079
|
+
if (typeof event.data !== "string")
|
|
4080
|
+
return;
|
|
4081
|
+
const msg = tryParseJson(event.data);
|
|
4082
|
+
if (!msg)
|
|
4083
|
+
return;
|
|
4084
|
+
const cmdId = "cmdId" in msg ? msg.cmdId : msg.event === "cmd-failed" ? msg.failedCmdId : void 0;
|
|
4085
|
+
const pendingCmd = context.pendingCmds.get(cmdId);
|
|
4086
|
+
if (cmdId && !pendingCmd) {
|
|
4087
|
+
warn("Ignoring unexpected command response. Already timed out, or not for us?", msg);
|
|
4088
|
+
return;
|
|
4089
|
+
}
|
|
4090
|
+
if ("event" in msg) {
|
|
4091
|
+
switch (msg.event) {
|
|
4092
|
+
case "cmd-failed":
|
|
4093
|
+
pendingCmd?.reject(new Error(msg.error));
|
|
4094
|
+
break;
|
|
4095
|
+
case "delta": {
|
|
4096
|
+
const { id, delta } = msg;
|
|
4097
|
+
context.messagesStore.addDelta(id, delta);
|
|
4098
|
+
break;
|
|
4099
|
+
}
|
|
4100
|
+
case "settle": {
|
|
4101
|
+
context.messagesStore.upsert(msg.message);
|
|
4102
|
+
break;
|
|
4103
|
+
}
|
|
4104
|
+
case "error":
|
|
4105
|
+
break;
|
|
4106
|
+
case "rebooted":
|
|
4107
|
+
context.messagesStore.failAllPending();
|
|
4108
|
+
break;
|
|
4109
|
+
case "sync":
|
|
4110
|
+
batch(() => {
|
|
4111
|
+
for (const m of msg["-messages"] ?? []) {
|
|
4112
|
+
context.messagesStore.remove(m.chatId, m.id);
|
|
4113
|
+
}
|
|
4114
|
+
for (const chatId of msg["-chats"] ?? []) {
|
|
4115
|
+
context.chatsStore.remove(chatId);
|
|
4116
|
+
context.messagesStore.removeByChatId(chatId);
|
|
4117
|
+
}
|
|
4118
|
+
for (const chatId of msg.clear ?? []) {
|
|
4119
|
+
context.messagesStore.removeByChatId(chatId);
|
|
4120
|
+
}
|
|
4121
|
+
if (msg.chats) {
|
|
4122
|
+
context.chatsStore.upsertMany(msg.chats);
|
|
4123
|
+
}
|
|
4124
|
+
if (msg.messages) {
|
|
4125
|
+
context.messagesStore.upsertMany(msg.messages);
|
|
4126
|
+
}
|
|
4127
|
+
});
|
|
4128
|
+
break;
|
|
4129
|
+
default:
|
|
4130
|
+
return assertNever(msg, "Unhandled case");
|
|
4131
|
+
}
|
|
4132
|
+
} else {
|
|
4133
|
+
switch (msg.cmd) {
|
|
4134
|
+
case "get-chats":
|
|
4135
|
+
context.chatsStore.upsertMany(msg.chats);
|
|
4136
|
+
break;
|
|
4137
|
+
case "create-chat":
|
|
4138
|
+
context.chatsStore.upsert(msg.chat);
|
|
4139
|
+
break;
|
|
4140
|
+
case "delete-chat":
|
|
4141
|
+
context.chatsStore.remove(msg.chatId);
|
|
4142
|
+
context.messagesStore.removeByChatId(msg.chatId);
|
|
4143
|
+
break;
|
|
4144
|
+
case "get-message-tree":
|
|
4145
|
+
context.chatsStore.upsert(msg.chat);
|
|
4146
|
+
context.messagesStore.upsertMany(msg.messages);
|
|
4147
|
+
break;
|
|
4148
|
+
case "add-user-message":
|
|
4149
|
+
context.messagesStore.upsert(msg.message);
|
|
4150
|
+
break;
|
|
4151
|
+
case "delete-message":
|
|
4152
|
+
context.messagesStore.remove(msg.chatId, msg.messageId);
|
|
4153
|
+
break;
|
|
4154
|
+
case "clear-chat":
|
|
4155
|
+
context.messagesStore.removeByChatId(msg.chatId);
|
|
4156
|
+
break;
|
|
4157
|
+
case "ask-ai":
|
|
4158
|
+
if (msg.message) {
|
|
4159
|
+
context.messagesStore.upsert(msg.message);
|
|
4160
|
+
} else {
|
|
4161
|
+
}
|
|
4162
|
+
break;
|
|
4163
|
+
case "abort-ai":
|
|
4164
|
+
break;
|
|
4165
|
+
default:
|
|
4166
|
+
return assertNever(msg, "Unhandled case");
|
|
4167
|
+
}
|
|
4168
|
+
}
|
|
4169
|
+
pendingCmd?.resolve(msg);
|
|
4170
|
+
}
|
|
4171
|
+
managedSocket.events.onMessage.subscribe(handleServerMessage);
|
|
4172
|
+
managedSocket.events.statusDidChange.subscribe(onStatusDidChange);
|
|
4173
|
+
managedSocket.events.statusDidChange.subscribe(handleConnectionLossEvent);
|
|
4174
|
+
managedSocket.events.didConnect.subscribe(onDidConnect);
|
|
4175
|
+
managedSocket.events.didDisconnect.subscribe(onDidDisconnect);
|
|
4176
|
+
managedSocket.events.onConnectionError.subscribe(({ message, code }) => {
|
|
4177
|
+
if (process.env.NODE_ENV !== "production") {
|
|
4178
|
+
error2(
|
|
4179
|
+
`Connection to websocket server closed. Reason: ${message} (code: ${code}).`
|
|
4180
|
+
);
|
|
4181
|
+
}
|
|
4182
|
+
});
|
|
4183
|
+
async function sendClientMsgWithResponse(msg) {
|
|
4184
|
+
if (managedSocket.getStatus() !== "connected") {
|
|
4185
|
+
await managedSocket.events.didConnect.waitUntil();
|
|
3181
4186
|
}
|
|
4187
|
+
const { promise, resolve, reject } = Promise_withResolvers();
|
|
4188
|
+
const abortSignal = AbortSignal.timeout(DEFAULT_REQUEST_TIMEOUT);
|
|
4189
|
+
abortSignal.addEventListener("abort", () => reject(abortSignal.reason), {
|
|
4190
|
+
once: true
|
|
4191
|
+
});
|
|
4192
|
+
const cmdId = nanoid(7);
|
|
4193
|
+
context.pendingCmds.set(cmdId, { resolve, reject });
|
|
4194
|
+
sendClientMsg({ ...msg, cmdId });
|
|
4195
|
+
return promise.finally(() => {
|
|
4196
|
+
context.pendingCmds.delete(cmdId);
|
|
4197
|
+
}).catch((err) => {
|
|
4198
|
+
error2(err.message);
|
|
4199
|
+
throw err;
|
|
4200
|
+
});
|
|
3182
4201
|
}
|
|
3183
|
-
|
|
3184
|
-
|
|
3185
|
-
|
|
3186
|
-
|
|
3187
|
-
|
|
3188
|
-
|
|
4202
|
+
function sendClientMsg(msg) {
|
|
4203
|
+
managedSocket.send(
|
|
4204
|
+
JSON.stringify({
|
|
4205
|
+
...msg
|
|
4206
|
+
})
|
|
4207
|
+
);
|
|
3189
4208
|
}
|
|
3190
|
-
}
|
|
3191
|
-
|
|
3192
|
-
|
|
3193
|
-
|
|
3194
|
-
|
|
3195
|
-
Permission2["Write"] = "room:write";
|
|
3196
|
-
Permission2["PresenceWrite"] = "room:presence:write";
|
|
3197
|
-
Permission2["CommentsWrite"] = "comments:write";
|
|
3198
|
-
Permission2["CommentsRead"] = "comments:read";
|
|
3199
|
-
return Permission2;
|
|
3200
|
-
})(Permission || {});
|
|
3201
|
-
function canWriteStorage(scopes) {
|
|
3202
|
-
return scopes.includes("room:write" /* Write */);
|
|
3203
|
-
}
|
|
3204
|
-
function canComment(scopes) {
|
|
3205
|
-
return scopes.includes("comments:write" /* CommentsWrite */) || scopes.includes("room:write" /* Write */);
|
|
3206
|
-
}
|
|
3207
|
-
function isValidAuthTokenPayload(data) {
|
|
3208
|
-
return isPlainObject(data) && (data.k === "acc" /* ACCESS_TOKEN */ || data.k === "id" /* ID_TOKEN */ || data.k === "sec-legacy" /* SECRET_LEGACY */);
|
|
3209
|
-
}
|
|
3210
|
-
function parseAuthToken(rawTokenString) {
|
|
3211
|
-
const tokenParts = rawTokenString.split(".");
|
|
3212
|
-
if (tokenParts.length !== 3) {
|
|
3213
|
-
throw new Error("Authentication error: invalid JWT token");
|
|
4209
|
+
function getChats(options = {}) {
|
|
4210
|
+
return sendClientMsgWithResponse({
|
|
4211
|
+
cmd: "get-chats",
|
|
4212
|
+
cursor: options.cursor
|
|
4213
|
+
});
|
|
3214
4214
|
}
|
|
3215
|
-
|
|
3216
|
-
|
|
3217
|
-
|
|
3218
|
-
|
|
4215
|
+
function createChat(id, name, options) {
|
|
4216
|
+
return sendClientMsgWithResponse({
|
|
4217
|
+
cmd: "create-chat",
|
|
4218
|
+
id,
|
|
4219
|
+
name,
|
|
4220
|
+
ephemeral: options?.ephemeral ?? false,
|
|
4221
|
+
metadata: options?.metadata ?? {}
|
|
4222
|
+
});
|
|
4223
|
+
}
|
|
4224
|
+
function getMessageTree(chatId) {
|
|
4225
|
+
return sendClientMsgWithResponse({
|
|
4226
|
+
cmd: "get-message-tree",
|
|
4227
|
+
chatId
|
|
4228
|
+
});
|
|
4229
|
+
}
|
|
4230
|
+
function registerChatContext(chatId, data) {
|
|
4231
|
+
const chatContext = context.contextByChatId.get(chatId);
|
|
4232
|
+
if (chatContext === void 0) {
|
|
4233
|
+
context.contextByChatId.set(chatId, /* @__PURE__ */ new Set([data]));
|
|
4234
|
+
} else {
|
|
4235
|
+
chatContext.add(data);
|
|
4236
|
+
}
|
|
4237
|
+
return () => {
|
|
4238
|
+
const chatContext2 = context.contextByChatId.get(chatId);
|
|
4239
|
+
if (chatContext2 !== void 0) {
|
|
4240
|
+
chatContext2.delete(data);
|
|
4241
|
+
if (chatContext2.size === 0) {
|
|
4242
|
+
context.contextByChatId.delete(chatId);
|
|
4243
|
+
}
|
|
4244
|
+
}
|
|
4245
|
+
};
|
|
4246
|
+
}
|
|
4247
|
+
function ask(chatId, messageId, options) {
|
|
4248
|
+
const targetMessageId = context.messagesStore.createOptimistically(
|
|
4249
|
+
chatId,
|
|
4250
|
+
"assistant",
|
|
4251
|
+
messageId
|
|
3219
4252
|
);
|
|
4253
|
+
const copilotId = options?.copilotId;
|
|
4254
|
+
const stream = options?.stream ?? false;
|
|
4255
|
+
const timeout = options?.timeout ?? DEFAULT_AI_TIMEOUT;
|
|
4256
|
+
const chatContext = context.contextByChatId.get(chatId);
|
|
4257
|
+
return sendClientMsgWithResponse({
|
|
4258
|
+
cmd: "ask-ai",
|
|
4259
|
+
chatId,
|
|
4260
|
+
sourceMessageId: messageId,
|
|
4261
|
+
targetMessageId,
|
|
4262
|
+
copilotId,
|
|
4263
|
+
clientId,
|
|
4264
|
+
stream,
|
|
4265
|
+
tools: context.toolsStore.getToolsForChat(chatId).map((tool) => ({
|
|
4266
|
+
name: tool.name,
|
|
4267
|
+
description: tool.definition.description,
|
|
4268
|
+
parameters: tool.definition.parameters
|
|
4269
|
+
})),
|
|
4270
|
+
timeout,
|
|
4271
|
+
context: chatContext ? Array.from(chatContext.values()) : void 0
|
|
4272
|
+
});
|
|
3220
4273
|
}
|
|
3221
|
-
return
|
|
3222
|
-
|
|
3223
|
-
|
|
4274
|
+
return Object.defineProperty(
|
|
4275
|
+
{
|
|
4276
|
+
[kInternal]: {
|
|
4277
|
+
debugContext: () => context
|
|
4278
|
+
},
|
|
4279
|
+
connect: () => managedSocket.connect(),
|
|
4280
|
+
reconnect: () => managedSocket.reconnect(),
|
|
4281
|
+
disconnect: () => managedSocket.disconnect(),
|
|
4282
|
+
getChats,
|
|
4283
|
+
createChat,
|
|
4284
|
+
deleteChat: (chatId) => {
|
|
4285
|
+
return sendClientMsgWithResponse({
|
|
4286
|
+
cmd: "delete-chat",
|
|
4287
|
+
chatId
|
|
4288
|
+
});
|
|
4289
|
+
},
|
|
4290
|
+
getMessageTree,
|
|
4291
|
+
deleteMessage: (chatId, messageId) => sendClientMsgWithResponse({ cmd: "delete-message", chatId, messageId }),
|
|
4292
|
+
clearChat: (chatId) => sendClientMsgWithResponse({ cmd: "clear-chat", chatId }),
|
|
4293
|
+
addUserMessage: (chatId, parentMessageId, message) => {
|
|
4294
|
+
const content = [{ type: "text", text: message }];
|
|
4295
|
+
const newMessageId = context.messagesStore.createOptimistically(
|
|
4296
|
+
chatId,
|
|
4297
|
+
"user",
|
|
4298
|
+
parentMessageId,
|
|
4299
|
+
content
|
|
4300
|
+
);
|
|
4301
|
+
return sendClientMsgWithResponse({
|
|
4302
|
+
cmd: "add-user-message",
|
|
4303
|
+
id: newMessageId,
|
|
4304
|
+
chatId,
|
|
4305
|
+
parentMessageId,
|
|
4306
|
+
content
|
|
4307
|
+
});
|
|
4308
|
+
},
|
|
4309
|
+
ask,
|
|
4310
|
+
regenerateMessage: (chatId, messageId, options) => {
|
|
4311
|
+
const parentUserMessageId = context.messagesStore.getLatestUserMessageAncestor(chatId, messageId);
|
|
4312
|
+
if (parentUserMessageId === null) {
|
|
4313
|
+
throw new Error(
|
|
4314
|
+
`Unable to find user message ancestor for messageId: ${messageId}`
|
|
4315
|
+
);
|
|
4316
|
+
}
|
|
4317
|
+
return ask(chatId, parentUserMessageId, options);
|
|
4318
|
+
},
|
|
4319
|
+
addUserMessageAndAsk: async (chatId, parentMessageId, message, options) => {
|
|
4320
|
+
const content = [{ type: "text", text: message }];
|
|
4321
|
+
const newMessageId = context.messagesStore.createOptimistically(
|
|
4322
|
+
chatId,
|
|
4323
|
+
"user",
|
|
4324
|
+
parentMessageId,
|
|
4325
|
+
content
|
|
4326
|
+
);
|
|
4327
|
+
const targetMessageId = context.messagesStore.createOptimistically(
|
|
4328
|
+
chatId,
|
|
4329
|
+
"assistant",
|
|
4330
|
+
newMessageId
|
|
4331
|
+
);
|
|
4332
|
+
await sendClientMsgWithResponse({
|
|
4333
|
+
cmd: "add-user-message",
|
|
4334
|
+
id: newMessageId,
|
|
4335
|
+
chatId,
|
|
4336
|
+
parentMessageId,
|
|
4337
|
+
content
|
|
4338
|
+
});
|
|
4339
|
+
const copilotId = options?.copilotId;
|
|
4340
|
+
const stream = options?.stream ?? false;
|
|
4341
|
+
const timeout = options?.timeout ?? DEFAULT_AI_TIMEOUT;
|
|
4342
|
+
const chatContext = context.contextByChatId.get(chatId);
|
|
4343
|
+
return sendClientMsgWithResponse({
|
|
4344
|
+
cmd: "ask-ai",
|
|
4345
|
+
chatId,
|
|
4346
|
+
sourceMessageId: newMessageId,
|
|
4347
|
+
targetMessageId,
|
|
4348
|
+
copilotId,
|
|
4349
|
+
clientId,
|
|
4350
|
+
stream,
|
|
4351
|
+
tools: context.toolsStore.getToolsForChat(chatId).map((tool) => ({
|
|
4352
|
+
name: tool.name,
|
|
4353
|
+
description: tool.definition.description,
|
|
4354
|
+
parameters: tool.definition.parameters
|
|
4355
|
+
})),
|
|
4356
|
+
timeout,
|
|
4357
|
+
context: chatContext ? Array.from(chatContext.values()) : void 0
|
|
4358
|
+
});
|
|
4359
|
+
},
|
|
4360
|
+
abort: (messageId) => sendClientMsgWithResponse({ cmd: "abort-ai", messageId }),
|
|
4361
|
+
getStatus: () => managedSocket.getStatus(),
|
|
4362
|
+
signals: {
|
|
4363
|
+
chats\u03A3: context.chatsStore.chats\u03A3,
|
|
4364
|
+
getChatMessagesForBranch\u03A3: context.messagesStore.getChatMessagesForBranch\u03A3,
|
|
4365
|
+
getToolDefinition\u03A3: context.toolsStore.getToolCallByName\u03A3,
|
|
4366
|
+
getMessagesForChat\u03A3: context.messagesStore.getMessagesForChat\u03A3
|
|
4367
|
+
},
|
|
4368
|
+
registerChatContext,
|
|
4369
|
+
registerChatTool: context.toolsStore.addToolDefinition,
|
|
4370
|
+
unregisterChatTool: context.toolsStore.removeToolDefinition
|
|
4371
|
+
},
|
|
4372
|
+
kInternal,
|
|
4373
|
+
{ enumerable: false }
|
|
4374
|
+
);
|
|
4375
|
+
}
|
|
4376
|
+
function makeCreateSocketDelegateForAi(baseUrl, WebSocketPolyfill) {
|
|
4377
|
+
return (authValue) => {
|
|
4378
|
+
const ws = WebSocketPolyfill ?? (typeof WebSocket === "undefined" ? void 0 : WebSocket);
|
|
4379
|
+
if (ws === void 0) {
|
|
4380
|
+
throw new StopRetrying(
|
|
4381
|
+
"To use Liveblocks client in a non-DOM environment, you need to provide a WebSocket polyfill."
|
|
4382
|
+
);
|
|
4383
|
+
}
|
|
4384
|
+
const url2 = new URL(baseUrl);
|
|
4385
|
+
url2.protocol = url2.protocol === "http:" ? "ws" : "wss";
|
|
4386
|
+
url2.pathname = "/ai/v1";
|
|
4387
|
+
if (authValue.type === "secret") {
|
|
4388
|
+
url2.searchParams.set("tok", authValue.token.raw);
|
|
4389
|
+
} else if (authValue.type === "public") {
|
|
4390
|
+
throw new Error("Public key not supported with AI Copilots");
|
|
4391
|
+
} else {
|
|
4392
|
+
return assertNever(authValue, "Unhandled case");
|
|
4393
|
+
}
|
|
4394
|
+
url2.searchParams.set("version", PKG_VERSION || "dev");
|
|
4395
|
+
return new ws(url2.toString());
|
|
3224
4396
|
};
|
|
3225
4397
|
}
|
|
3226
4398
|
|
|
@@ -3246,11 +4418,11 @@ function createAuthManager(authOptions, onAuthenticate) {
|
|
|
3246
4418
|
return false;
|
|
3247
4419
|
}
|
|
3248
4420
|
function getCachedToken(requestOptions) {
|
|
3249
|
-
const
|
|
4421
|
+
const now2 = Math.ceil(Date.now() / 1e3);
|
|
3250
4422
|
for (let i = tokens.length - 1; i >= 0; i--) {
|
|
3251
4423
|
const token = tokens[i];
|
|
3252
4424
|
const expiresAt = expiryTimes[i];
|
|
3253
|
-
if (expiresAt <=
|
|
4425
|
+
if (expiresAt <= now2) {
|
|
3254
4426
|
tokens.splice(i, 1);
|
|
3255
4427
|
expiryTimes.splice(i, 1);
|
|
3256
4428
|
continue;
|
|
@@ -3444,9 +4616,6 @@ async function fetchAuthEndpoint(fetch, endpoint, body) {
|
|
|
3444
4616
|
// src/constants.ts
|
|
3445
4617
|
var DEFAULT_BASE_URL = "https://api.liveblocks.io";
|
|
3446
4618
|
|
|
3447
|
-
// src/internal.ts
|
|
3448
|
-
var kInternal = Symbol();
|
|
3449
|
-
|
|
3450
4619
|
// src/devtools/bridge.ts
|
|
3451
4620
|
var _bridgeActive = false;
|
|
3452
4621
|
function activateBridge(allowed) {
|
|
@@ -6561,6 +7730,14 @@ function defaultMessageFromContext(context) {
|
|
|
6561
7730
|
return "Could not connect to the room";
|
|
6562
7731
|
}
|
|
6563
7732
|
}
|
|
7733
|
+
case "AI_CONNECTION_ERROR": {
|
|
7734
|
+
switch (context.code) {
|
|
7735
|
+
case 4001:
|
|
7736
|
+
return "Not allowed to connect to ai";
|
|
7737
|
+
default:
|
|
7738
|
+
return "Could not connect to the room";
|
|
7739
|
+
}
|
|
7740
|
+
}
|
|
6564
7741
|
case "CREATE_THREAD_ERROR":
|
|
6565
7742
|
return "Could not create new thread";
|
|
6566
7743
|
case "DELETE_THREAD_ERROR":
|
|
@@ -7440,8 +8617,8 @@ ${Array.from(traces).join("\n\n")}`
|
|
|
7440
8617
|
context.buffer.storageOperations = [];
|
|
7441
8618
|
return;
|
|
7442
8619
|
}
|
|
7443
|
-
const
|
|
7444
|
-
const elapsedMillis =
|
|
8620
|
+
const now2 = Date.now();
|
|
8621
|
+
const elapsedMillis = now2 - context.buffer.lastFlushedAt;
|
|
7445
8622
|
if (elapsedMillis >= config.throttleDelay) {
|
|
7446
8623
|
const messagesToFlush = serializeBuffer();
|
|
7447
8624
|
if (messagesToFlush.length === 0) {
|
|
@@ -7450,7 +8627,7 @@ ${Array.from(traces).join("\n\n")}`
|
|
|
7450
8627
|
sendMessages(messagesToFlush);
|
|
7451
8628
|
context.buffer = {
|
|
7452
8629
|
flushTimerID: void 0,
|
|
7453
|
-
lastFlushedAt:
|
|
8630
|
+
lastFlushedAt: now2,
|
|
7454
8631
|
messages: [],
|
|
7455
8632
|
storageOperations: [],
|
|
7456
8633
|
presenceUpdates: null
|
|
@@ -8177,9 +9354,26 @@ function createClient(options) {
|
|
|
8177
9354
|
const httpClient = createApiClient({
|
|
8178
9355
|
baseUrl,
|
|
8179
9356
|
fetchPolyfill,
|
|
9357
|
+
currentUserId,
|
|
8180
9358
|
authManager
|
|
8181
9359
|
});
|
|
8182
9360
|
const roomsById = /* @__PURE__ */ new Map();
|
|
9361
|
+
const ai = createAi({
|
|
9362
|
+
userId: currentUserId.get(),
|
|
9363
|
+
lostConnectionTimeout,
|
|
9364
|
+
backgroundKeepAliveTimeout: getBackgroundKeepAliveTimeout(
|
|
9365
|
+
clientOptions.backgroundKeepAliveTimeout
|
|
9366
|
+
),
|
|
9367
|
+
polyfills: clientOptions.polyfills,
|
|
9368
|
+
delegates: {
|
|
9369
|
+
createSocket: makeCreateSocketDelegateForAi(
|
|
9370
|
+
baseUrl,
|
|
9371
|
+
clientOptions.polyfills?.WebSocket
|
|
9372
|
+
),
|
|
9373
|
+
authenticate: makeAuthDelegateForRoom("default", authManager),
|
|
9374
|
+
canZombie: () => true
|
|
9375
|
+
}
|
|
9376
|
+
});
|
|
8183
9377
|
function teardownRoom(room) {
|
|
8184
9378
|
unlinkDevTools(room.id);
|
|
8185
9379
|
roomsById.delete(room.id);
|
|
@@ -8393,6 +9587,7 @@ function createClient(options) {
|
|
|
8393
9587
|
[kInternal]: {
|
|
8394
9588
|
currentUserId,
|
|
8395
9589
|
mentionSuggestionsCache,
|
|
9590
|
+
ai,
|
|
8396
9591
|
resolveMentionSuggestions: clientOptions.resolveMentionSuggestions,
|
|
8397
9592
|
usersStore,
|
|
8398
9593
|
roomsInfoStore,
|
|
@@ -9269,129 +10464,6 @@ function makePoller(callback, intervalMs, options) {
|
|
|
9269
10464
|
};
|
|
9270
10465
|
}
|
|
9271
10466
|
|
|
9272
|
-
// src/lib/shallow.ts
|
|
9273
|
-
function shallowArray(xs, ys) {
|
|
9274
|
-
if (xs.length !== ys.length) {
|
|
9275
|
-
return false;
|
|
9276
|
-
}
|
|
9277
|
-
for (let i = 0; i < xs.length; i++) {
|
|
9278
|
-
if (!Object.is(xs[i], ys[i])) {
|
|
9279
|
-
return false;
|
|
9280
|
-
}
|
|
9281
|
-
}
|
|
9282
|
-
return true;
|
|
9283
|
-
}
|
|
9284
|
-
function shallowObj(objA, objB) {
|
|
9285
|
-
if (!isPlainObject(objA) || !isPlainObject(objB)) {
|
|
9286
|
-
return false;
|
|
9287
|
-
}
|
|
9288
|
-
const keysA = Object.keys(objA);
|
|
9289
|
-
if (keysA.length !== Object.keys(objB).length) {
|
|
9290
|
-
return false;
|
|
9291
|
-
}
|
|
9292
|
-
return keysA.every(
|
|
9293
|
-
(key) => Object.prototype.hasOwnProperty.call(objB, key) && Object.is(objA[key], objB[key])
|
|
9294
|
-
);
|
|
9295
|
-
}
|
|
9296
|
-
function shallow(a, b) {
|
|
9297
|
-
if (Object.is(a, b)) {
|
|
9298
|
-
return true;
|
|
9299
|
-
}
|
|
9300
|
-
const isArrayA = Array.isArray(a);
|
|
9301
|
-
const isArrayB = Array.isArray(b);
|
|
9302
|
-
if (isArrayA || isArrayB) {
|
|
9303
|
-
if (!isArrayA || !isArrayB) {
|
|
9304
|
-
return false;
|
|
9305
|
-
}
|
|
9306
|
-
return shallowArray(a, b);
|
|
9307
|
-
}
|
|
9308
|
-
return shallowObj(a, b);
|
|
9309
|
-
}
|
|
9310
|
-
function shallow2(a, b) {
|
|
9311
|
-
if (!isPlainObject(a) || !isPlainObject(b)) {
|
|
9312
|
-
return shallow(a, b);
|
|
9313
|
-
}
|
|
9314
|
-
const keysA = Object.keys(a);
|
|
9315
|
-
if (keysA.length !== Object.keys(b).length) {
|
|
9316
|
-
return false;
|
|
9317
|
-
}
|
|
9318
|
-
return keysA.every(
|
|
9319
|
-
(key) => Object.prototype.hasOwnProperty.call(b, key) && shallow(a[key], b[key])
|
|
9320
|
-
);
|
|
9321
|
-
}
|
|
9322
|
-
|
|
9323
|
-
// src/lib/SortedList.ts
|
|
9324
|
-
function bisectRight(arr, x, lt) {
|
|
9325
|
-
let lo = 0;
|
|
9326
|
-
let hi = arr.length;
|
|
9327
|
-
while (lo < hi) {
|
|
9328
|
-
const mid = lo + (hi - lo >> 1);
|
|
9329
|
-
if (lt(x, arr[mid])) {
|
|
9330
|
-
hi = mid;
|
|
9331
|
-
} else {
|
|
9332
|
-
lo = mid + 1;
|
|
9333
|
-
}
|
|
9334
|
-
}
|
|
9335
|
-
return lo;
|
|
9336
|
-
}
|
|
9337
|
-
var SortedList = class _SortedList {
|
|
9338
|
-
#data;
|
|
9339
|
-
#lt;
|
|
9340
|
-
constructor(alreadySortedList, lt) {
|
|
9341
|
-
this.#lt = lt;
|
|
9342
|
-
this.#data = alreadySortedList;
|
|
9343
|
-
}
|
|
9344
|
-
static from(arr, lt) {
|
|
9345
|
-
const sorted = new _SortedList([], lt);
|
|
9346
|
-
for (const item of arr) {
|
|
9347
|
-
sorted.add(item);
|
|
9348
|
-
}
|
|
9349
|
-
return sorted;
|
|
9350
|
-
}
|
|
9351
|
-
static fromAlreadySorted(alreadySorted, lt) {
|
|
9352
|
-
return new _SortedList(alreadySorted, lt);
|
|
9353
|
-
}
|
|
9354
|
-
/**
|
|
9355
|
-
* Clones the sorted list to a new instance.
|
|
9356
|
-
*/
|
|
9357
|
-
clone() {
|
|
9358
|
-
return new _SortedList(this.#data.slice(), this.#lt);
|
|
9359
|
-
}
|
|
9360
|
-
/**
|
|
9361
|
-
* Adds a new item to the sorted list, such that it remains sorted.
|
|
9362
|
-
*/
|
|
9363
|
-
add(value) {
|
|
9364
|
-
const idx = bisectRight(this.#data, value, this.#lt);
|
|
9365
|
-
this.#data.splice(idx, 0, value);
|
|
9366
|
-
}
|
|
9367
|
-
/**
|
|
9368
|
-
* Removes the given value from the sorted list, if it exists. The given
|
|
9369
|
-
* value must be `===` to one of the list items. Only the first entry will be
|
|
9370
|
-
* removed if the element exists in the sorted list multiple times.
|
|
9371
|
-
*/
|
|
9372
|
-
remove(value) {
|
|
9373
|
-
const idx = this.#data.indexOf(value);
|
|
9374
|
-
if (idx >= 0) {
|
|
9375
|
-
this.#data.splice(idx, 1);
|
|
9376
|
-
return true;
|
|
9377
|
-
}
|
|
9378
|
-
return false;
|
|
9379
|
-
}
|
|
9380
|
-
get length() {
|
|
9381
|
-
return this.#data.length;
|
|
9382
|
-
}
|
|
9383
|
-
*filter(predicate) {
|
|
9384
|
-
for (const item of this.#data) {
|
|
9385
|
-
if (predicate(item)) {
|
|
9386
|
-
yield item;
|
|
9387
|
-
}
|
|
9388
|
-
}
|
|
9389
|
-
}
|
|
9390
|
-
[Symbol.iterator]() {
|
|
9391
|
-
return this.#data[Symbol.iterator]();
|
|
9392
|
-
}
|
|
9393
|
-
};
|
|
9394
|
-
|
|
9395
10467
|
// src/protocol/Subscriptions.ts
|
|
9396
10468
|
function getSubscriptionKey(subscription, subjectId) {
|
|
9397
10469
|
if (typeof subscription === "string") {
|