@liveblocks/core 1.19.0-test1 → 2.0.0-alpha2
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 +1103 -859
- package/dist/index.d.ts +1103 -859
- package/dist/index.js +2037 -942
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +2505 -1410
- package/dist/index.mjs.map +1 -1
- package/package.json +4 -2
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 = "
|
|
9
|
+
var PKG_VERSION = "2.0.0-alpha2";
|
|
10
10
|
var PKG_FORMAT = "esm";
|
|
11
11
|
|
|
12
12
|
// src/dupe-detection.ts
|
|
@@ -362,23 +362,29 @@ var FSM = class {
|
|
|
362
362
|
}
|
|
363
363
|
onEnterAsync(nameOrPattern, promiseFn, onOK, onError) {
|
|
364
364
|
return this.onEnter(nameOrPattern, () => {
|
|
365
|
-
|
|
366
|
-
|
|
365
|
+
const abortController = new AbortController();
|
|
366
|
+
const signal = abortController.signal;
|
|
367
|
+
let done = false;
|
|
368
|
+
void promiseFn(this.currentContext.current, signal).then(
|
|
367
369
|
// On OK
|
|
368
370
|
(data) => {
|
|
369
|
-
if (!
|
|
371
|
+
if (!signal.aborted) {
|
|
372
|
+
done = true;
|
|
370
373
|
this.transition({ type: "ASYNC_OK", data }, onOK);
|
|
371
374
|
}
|
|
372
375
|
},
|
|
373
376
|
// On Error
|
|
374
377
|
(reason) => {
|
|
375
|
-
if (!
|
|
378
|
+
if (!signal.aborted) {
|
|
379
|
+
done = true;
|
|
376
380
|
this.transition({ type: "ASYNC_ERROR", reason }, onError);
|
|
377
381
|
}
|
|
378
382
|
}
|
|
379
383
|
);
|
|
380
384
|
return () => {
|
|
381
|
-
|
|
385
|
+
if (!done) {
|
|
386
|
+
abortController.abort();
|
|
387
|
+
}
|
|
382
388
|
};
|
|
383
389
|
});
|
|
384
390
|
}
|
|
@@ -652,6 +658,7 @@ var ServerMsgCode = /* @__PURE__ */ ((ServerMsgCode2) => {
|
|
|
652
658
|
|
|
653
659
|
// src/types/IWebSocket.ts
|
|
654
660
|
var WebsocketCloseCodes = /* @__PURE__ */ ((WebsocketCloseCodes2) => {
|
|
661
|
+
WebsocketCloseCodes2[WebsocketCloseCodes2["CLOSE_NORMAL"] = 1e3] = "CLOSE_NORMAL";
|
|
655
662
|
WebsocketCloseCodes2[WebsocketCloseCodes2["CLOSE_ABNORMAL"] = 1006] = "CLOSE_ABNORMAL";
|
|
656
663
|
WebsocketCloseCodes2[WebsocketCloseCodes2["UNEXPECTED_CONDITION"] = 1011] = "UNEXPECTED_CONDITION";
|
|
657
664
|
WebsocketCloseCodes2[WebsocketCloseCodes2["TRY_AGAIN_LATER"] = 1013] = "TRY_AGAIN_LATER";
|
|
@@ -661,6 +668,8 @@ var WebsocketCloseCodes = /* @__PURE__ */ ((WebsocketCloseCodes2) => {
|
|
|
661
668
|
WebsocketCloseCodes2[WebsocketCloseCodes2["MAX_NUMBER_OF_CONCURRENT_CONNECTIONS"] = 4003] = "MAX_NUMBER_OF_CONCURRENT_CONNECTIONS";
|
|
662
669
|
WebsocketCloseCodes2[WebsocketCloseCodes2["MAX_NUMBER_OF_MESSAGES_PER_DAY_PER_APP"] = 4004] = "MAX_NUMBER_OF_MESSAGES_PER_DAY_PER_APP";
|
|
663
670
|
WebsocketCloseCodes2[WebsocketCloseCodes2["MAX_NUMBER_OF_CONCURRENT_CONNECTIONS_PER_ROOM"] = 4005] = "MAX_NUMBER_OF_CONCURRENT_CONNECTIONS_PER_ROOM";
|
|
671
|
+
WebsocketCloseCodes2[WebsocketCloseCodes2["ROOM_ID_UPDATED"] = 4006] = "ROOM_ID_UPDATED";
|
|
672
|
+
WebsocketCloseCodes2[WebsocketCloseCodes2["KICKED"] = 4100] = "KICKED";
|
|
664
673
|
WebsocketCloseCodes2[WebsocketCloseCodes2["TOKEN_EXPIRED"] = 4109] = "TOKEN_EXPIRED";
|
|
665
674
|
WebsocketCloseCodes2[WebsocketCloseCodes2["CLOSE_WITHOUT_RETRY"] = 4999] = "CLOSE_WITHOUT_RETRY";
|
|
666
675
|
return WebsocketCloseCodes2;
|
|
@@ -679,22 +688,6 @@ function shouldRetryWithoutReauth(code) {
|
|
|
679
688
|
function isIdle(status) {
|
|
680
689
|
return status === "initial" || status === "disconnected";
|
|
681
690
|
}
|
|
682
|
-
function newToLegacyStatus(status) {
|
|
683
|
-
switch (status) {
|
|
684
|
-
case "connecting":
|
|
685
|
-
return "connecting";
|
|
686
|
-
case "connected":
|
|
687
|
-
return "open";
|
|
688
|
-
case "reconnecting":
|
|
689
|
-
return "unavailable";
|
|
690
|
-
case "disconnected":
|
|
691
|
-
return "failed";
|
|
692
|
-
case "initial":
|
|
693
|
-
return "closed";
|
|
694
|
-
default:
|
|
695
|
-
return "closed";
|
|
696
|
-
}
|
|
697
|
-
}
|
|
698
691
|
function toNewConnectionStatus(machine) {
|
|
699
692
|
const state = machine.currentState;
|
|
700
693
|
switch (state) {
|
|
@@ -728,16 +721,19 @@ var StopRetrying = class extends Error {
|
|
|
728
721
|
}
|
|
729
722
|
};
|
|
730
723
|
var LiveblocksError = class extends Error {
|
|
724
|
+
/** @internal */
|
|
731
725
|
constructor(message, code) {
|
|
732
726
|
super(message);
|
|
733
727
|
this.code = code;
|
|
734
728
|
}
|
|
735
729
|
};
|
|
736
|
-
function nextBackoffDelay(currentDelay, delays
|
|
730
|
+
function nextBackoffDelay(currentDelay, delays) {
|
|
737
731
|
return delays.find((delay) => delay > currentDelay) ?? delays[delays.length - 1];
|
|
738
732
|
}
|
|
739
733
|
function increaseBackoffDelay(context) {
|
|
740
|
-
context.patch({
|
|
734
|
+
context.patch({
|
|
735
|
+
backoffDelay: nextBackoffDelay(context.backoffDelay, BACKOFF_DELAYS)
|
|
736
|
+
});
|
|
741
737
|
}
|
|
742
738
|
function increaseBackoffDelayAggressively(context) {
|
|
743
739
|
context.patch({
|
|
@@ -770,9 +766,13 @@ function logPrematureErrorOrCloseEvent(e) {
|
|
|
770
766
|
};
|
|
771
767
|
}
|
|
772
768
|
function logCloseEvent(event) {
|
|
769
|
+
const details = [`code: ${event.code}`];
|
|
770
|
+
if (event.reason) {
|
|
771
|
+
details.push(`reason: ${event.reason}`);
|
|
772
|
+
}
|
|
773
773
|
return (ctx) => {
|
|
774
774
|
warn(
|
|
775
|
-
`Connection to Liveblocks websocket server closed (
|
|
775
|
+
`Connection to Liveblocks websocket server closed (${details.join(", ")}). Retrying in ${ctx.backoffDelay}ms.`
|
|
776
776
|
);
|
|
777
777
|
};
|
|
778
778
|
}
|
|
@@ -884,8 +884,7 @@ function createConnectionStateMachine(delegates, options) {
|
|
|
884
884
|
(okEvent) => ({
|
|
885
885
|
target: "@connecting.busy",
|
|
886
886
|
effect: assign({
|
|
887
|
-
authValue: okEvent.data
|
|
888
|
-
backoffDelay: RESET_DELAY
|
|
887
|
+
authValue: okEvent.data
|
|
889
888
|
})
|
|
890
889
|
}),
|
|
891
890
|
// Auth failed
|
|
@@ -942,14 +941,16 @@ function createConnectionStateMachine(delegates, options) {
|
|
|
942
941
|
// When the "open" event happens, we're ready to transition to the
|
|
943
942
|
// OK state. This is done by resolving the Promise.
|
|
944
943
|
//
|
|
945
|
-
async (ctx) => {
|
|
944
|
+
async (ctx, signal) => {
|
|
946
945
|
let capturedPrematureEvent = null;
|
|
946
|
+
let unconfirmedSocket = null;
|
|
947
947
|
const connect$ = new Promise(
|
|
948
948
|
(resolve, rej) => {
|
|
949
949
|
if (ctx.authValue === null) {
|
|
950
950
|
throw new Error("No auth authValue");
|
|
951
951
|
}
|
|
952
952
|
const socket = delegates.createSocket(ctx.authValue);
|
|
953
|
+
unconfirmedSocket = socket;
|
|
953
954
|
function reject(event) {
|
|
954
955
|
capturedPrematureEvent = event;
|
|
955
956
|
socket.removeEventListener("message", onSocketMessage);
|
|
@@ -1005,12 +1006,18 @@ function createConnectionStateMachine(delegates, options) {
|
|
|
1005
1006
|
//
|
|
1006
1007
|
([socket, unsub]) => {
|
|
1007
1008
|
unsub();
|
|
1009
|
+
if (signal.aborted) {
|
|
1010
|
+
throw new Error("Aborted");
|
|
1011
|
+
}
|
|
1008
1012
|
if (capturedPrematureEvent) {
|
|
1009
1013
|
throw capturedPrematureEvent;
|
|
1010
1014
|
}
|
|
1011
1015
|
return socket;
|
|
1012
1016
|
}
|
|
1013
|
-
)
|
|
1017
|
+
).catch((e) => {
|
|
1018
|
+
teardownSocket(unconfirmedSocket);
|
|
1019
|
+
throw e;
|
|
1020
|
+
});
|
|
1014
1021
|
},
|
|
1015
1022
|
// Only transition to OK state after a successfully opened WebSocket connection
|
|
1016
1023
|
(okEvent) => ({
|
|
@@ -1205,9 +1212,6 @@ var ManagedSocket = class {
|
|
|
1205
1212
|
this.events = events;
|
|
1206
1213
|
this.cleanups = cleanups;
|
|
1207
1214
|
}
|
|
1208
|
-
getLegacyStatus() {
|
|
1209
|
-
return newToLegacyStatus(this.getStatus());
|
|
1210
|
-
}
|
|
1211
1215
|
getStatus() {
|
|
1212
1216
|
try {
|
|
1213
1217
|
return toNewConnectionStatus(this.machine);
|
|
@@ -1325,7 +1329,7 @@ function createAuthManager(authOptions) {
|
|
|
1325
1329
|
}
|
|
1326
1330
|
return false;
|
|
1327
1331
|
}
|
|
1328
|
-
function getCachedToken(
|
|
1332
|
+
function getCachedToken(requestOptions) {
|
|
1329
1333
|
const now = Math.ceil(Date.now() / 1e3);
|
|
1330
1334
|
for (let i = tokens.length - 1; i >= 0; i--) {
|
|
1331
1335
|
const token = tokens[i];
|
|
@@ -1338,8 +1342,15 @@ function createAuthManager(authOptions) {
|
|
|
1338
1342
|
if (token.parsed.k === "id" /* ID_TOKEN */) {
|
|
1339
1343
|
return token;
|
|
1340
1344
|
} else if (token.parsed.k === "acc" /* ACCESS_TOKEN */) {
|
|
1345
|
+
if (!requestOptions.roomId && Object.entries(token.parsed.perms).length === 0) {
|
|
1346
|
+
return token;
|
|
1347
|
+
}
|
|
1341
1348
|
for (const [resource, scopes] of Object.entries(token.parsed.perms)) {
|
|
1342
|
-
if (
|
|
1349
|
+
if (!requestOptions.roomId) {
|
|
1350
|
+
if (resource.includes("*") && hasCorrespondingScopes(requestOptions.requestedScope, scopes)) {
|
|
1351
|
+
return token;
|
|
1352
|
+
}
|
|
1353
|
+
} else if (resource.includes("*") && requestOptions.roomId.startsWith(resource.replace("*", "")) || requestOptions.roomId === resource && hasCorrespondingScopes(requestOptions.requestedScope, scopes)) {
|
|
1343
1354
|
return token;
|
|
1344
1355
|
}
|
|
1345
1356
|
}
|
|
@@ -1347,7 +1358,7 @@ function createAuthManager(authOptions) {
|
|
|
1347
1358
|
}
|
|
1348
1359
|
return void 0;
|
|
1349
1360
|
}
|
|
1350
|
-
async function makeAuthRequest(
|
|
1361
|
+
async function makeAuthRequest(options) {
|
|
1351
1362
|
const fetcher = authOptions.polyfills?.fetch ?? (typeof window === "undefined" ? void 0 : window.fetch);
|
|
1352
1363
|
if (authentication.type === "private") {
|
|
1353
1364
|
if (fetcher === void 0) {
|
|
@@ -1356,7 +1367,7 @@ function createAuthManager(authOptions) {
|
|
|
1356
1367
|
);
|
|
1357
1368
|
}
|
|
1358
1369
|
const response = await fetchAuthEndpoint(fetcher, authentication.url, {
|
|
1359
|
-
room: roomId
|
|
1370
|
+
room: options.roomId
|
|
1360
1371
|
});
|
|
1361
1372
|
const parsed = parseAuthToken(response.token);
|
|
1362
1373
|
if (seenTokens.has(parsed.raw)) {
|
|
@@ -1367,10 +1378,11 @@ function createAuthManager(authOptions) {
|
|
|
1367
1378
|
return parsed;
|
|
1368
1379
|
}
|
|
1369
1380
|
if (authentication.type === "custom") {
|
|
1370
|
-
const response = await authentication.callback(roomId);
|
|
1381
|
+
const response = await authentication.callback(options.roomId);
|
|
1371
1382
|
if (response && typeof response === "object") {
|
|
1372
1383
|
if (typeof response.token === "string") {
|
|
1373
|
-
|
|
1384
|
+
const parsed = parseAuthToken(response.token);
|
|
1385
|
+
return parsed;
|
|
1374
1386
|
} else if (typeof response.error === "string") {
|
|
1375
1387
|
const reason = `Authentication failed: ${"reason" in response && typeof response.reason === "string" ? response.reason : "Forbidden"}`;
|
|
1376
1388
|
if (response.error === "forbidden") {
|
|
@@ -1388,18 +1400,27 @@ function createAuthManager(authOptions) {
|
|
|
1388
1400
|
"Unexpected authentication type. Must be private or custom."
|
|
1389
1401
|
);
|
|
1390
1402
|
}
|
|
1391
|
-
async function getAuthValue(
|
|
1403
|
+
async function getAuthValue(requestOptions) {
|
|
1392
1404
|
if (authentication.type === "public") {
|
|
1393
1405
|
return { type: "public", publicApiKey: authentication.publicApiKey };
|
|
1394
1406
|
}
|
|
1395
|
-
const cachedToken = getCachedToken(
|
|
1407
|
+
const cachedToken = getCachedToken(requestOptions);
|
|
1396
1408
|
if (cachedToken !== void 0) {
|
|
1397
1409
|
return { type: "secret", token: cachedToken };
|
|
1398
1410
|
}
|
|
1399
|
-
let currentPromise
|
|
1400
|
-
if (
|
|
1401
|
-
currentPromise =
|
|
1402
|
-
|
|
1411
|
+
let currentPromise;
|
|
1412
|
+
if (requestOptions.roomId) {
|
|
1413
|
+
currentPromise = requestPromises.get(requestOptions.roomId);
|
|
1414
|
+
if (currentPromise === void 0) {
|
|
1415
|
+
currentPromise = makeAuthRequest(requestOptions);
|
|
1416
|
+
requestPromises.set(requestOptions.roomId, currentPromise);
|
|
1417
|
+
}
|
|
1418
|
+
} else {
|
|
1419
|
+
currentPromise = requestPromises.get("liveblocks-user-token");
|
|
1420
|
+
if (currentPromise === void 0) {
|
|
1421
|
+
currentPromise = makeAuthRequest(requestOptions);
|
|
1422
|
+
requestPromises.set("liveblocks-user-token", currentPromise);
|
|
1423
|
+
}
|
|
1403
1424
|
}
|
|
1404
1425
|
try {
|
|
1405
1426
|
const token = await currentPromise;
|
|
@@ -1412,7 +1433,11 @@ function createAuthManager(authOptions) {
|
|
|
1412
1433
|
}
|
|
1413
1434
|
return { type: "secret", token };
|
|
1414
1435
|
} finally {
|
|
1415
|
-
|
|
1436
|
+
if (requestOptions.roomId) {
|
|
1437
|
+
requestPromises.delete(requestOptions.roomId);
|
|
1438
|
+
} else {
|
|
1439
|
+
requestPromises.delete("liveblocks-user-token");
|
|
1440
|
+
}
|
|
1416
1441
|
}
|
|
1417
1442
|
}
|
|
1418
1443
|
return {
|
|
@@ -1501,6 +1526,9 @@ async function fetchAuthEndpoint(fetch2, endpoint, body) {
|
|
|
1501
1526
|
// src/constants.ts
|
|
1502
1527
|
var DEFAULT_BASE_URL = "https://api.liveblocks.io";
|
|
1503
1528
|
|
|
1529
|
+
// src/internal.ts
|
|
1530
|
+
var kInternal = Symbol();
|
|
1531
|
+
|
|
1504
1532
|
// src/devtools/bridge.ts
|
|
1505
1533
|
var _bridgeActive = false;
|
|
1506
1534
|
function activateBridge(allowed) {
|
|
@@ -1630,7 +1658,7 @@ function partialSyncStorage(room) {
|
|
|
1630
1658
|
}
|
|
1631
1659
|
}
|
|
1632
1660
|
function partialSyncMe(room) {
|
|
1633
|
-
const me = room.
|
|
1661
|
+
const me = room[kInternal].getSelf_forDevTools();
|
|
1634
1662
|
if (me) {
|
|
1635
1663
|
sendToPanel({
|
|
1636
1664
|
msg: "room::sync::partial",
|
|
@@ -1640,7 +1668,7 @@ function partialSyncMe(room) {
|
|
|
1640
1668
|
}
|
|
1641
1669
|
}
|
|
1642
1670
|
function partialSyncOthers(room) {
|
|
1643
|
-
const others = room.
|
|
1671
|
+
const others = room[kInternal].getOthers_forDevTools();
|
|
1644
1672
|
if (others) {
|
|
1645
1673
|
sendToPanel({
|
|
1646
1674
|
msg: "room::sync::partial",
|
|
@@ -1651,8 +1679,8 @@ function partialSyncOthers(room) {
|
|
|
1651
1679
|
}
|
|
1652
1680
|
function fullSync(room) {
|
|
1653
1681
|
const root = room.getStorageSnapshot();
|
|
1654
|
-
const me = room.
|
|
1655
|
-
const others = room.
|
|
1682
|
+
const me = room[kInternal].getSelf_forDevTools();
|
|
1683
|
+
const others = room[kInternal].getOthers_forDevTools();
|
|
1656
1684
|
room.fetchYDoc("");
|
|
1657
1685
|
sendToPanel({
|
|
1658
1686
|
msg: "room::sync::full",
|
|
@@ -1711,6 +1739,183 @@ function unlinkDevTools(roomId) {
|
|
|
1711
1739
|
});
|
|
1712
1740
|
}
|
|
1713
1741
|
|
|
1742
|
+
// src/lib/stringify.ts
|
|
1743
|
+
function stringify(object, ...args) {
|
|
1744
|
+
if (typeof object !== "object" || object === null || Array.isArray(object)) {
|
|
1745
|
+
return JSON.stringify(object, ...args);
|
|
1746
|
+
}
|
|
1747
|
+
const sortedObject = Object.keys(object).sort().reduce(
|
|
1748
|
+
(sortedObject2, key) => {
|
|
1749
|
+
sortedObject2[key] = object[key];
|
|
1750
|
+
return sortedObject2;
|
|
1751
|
+
},
|
|
1752
|
+
{}
|
|
1753
|
+
);
|
|
1754
|
+
return JSON.stringify(sortedObject, ...args);
|
|
1755
|
+
}
|
|
1756
|
+
|
|
1757
|
+
// src/lib/batch.ts
|
|
1758
|
+
var DEFAULT_SIZE = 50;
|
|
1759
|
+
var DEFAULT_DELAY = 100;
|
|
1760
|
+
var noop = () => {
|
|
1761
|
+
};
|
|
1762
|
+
var BatchCall = class {
|
|
1763
|
+
constructor(args) {
|
|
1764
|
+
this.resolve = noop;
|
|
1765
|
+
this.reject = noop;
|
|
1766
|
+
this.promise = new Promise(noop);
|
|
1767
|
+
this.args = args;
|
|
1768
|
+
}
|
|
1769
|
+
};
|
|
1770
|
+
var Batch = class {
|
|
1771
|
+
constructor(callback, options) {
|
|
1772
|
+
this.queue = [];
|
|
1773
|
+
this.error = false;
|
|
1774
|
+
this.callback = callback;
|
|
1775
|
+
this.size = options?.size ?? DEFAULT_SIZE;
|
|
1776
|
+
this.delay = options?.delay ?? DEFAULT_DELAY;
|
|
1777
|
+
}
|
|
1778
|
+
clearDelayTimeout() {
|
|
1779
|
+
if (this.delayTimeoutId !== void 0) {
|
|
1780
|
+
clearTimeout(this.delayTimeoutId);
|
|
1781
|
+
this.delayTimeoutId = void 0;
|
|
1782
|
+
}
|
|
1783
|
+
}
|
|
1784
|
+
schedule() {
|
|
1785
|
+
if (this.queue.length === this.size) {
|
|
1786
|
+
void this.flush();
|
|
1787
|
+
} else if (this.queue.length === 1) {
|
|
1788
|
+
this.clearDelayTimeout();
|
|
1789
|
+
this.delayTimeoutId = setTimeout(() => void this.flush(), this.delay);
|
|
1790
|
+
}
|
|
1791
|
+
}
|
|
1792
|
+
async flush() {
|
|
1793
|
+
if (this.queue.length === 0) {
|
|
1794
|
+
return;
|
|
1795
|
+
}
|
|
1796
|
+
const calls = this.queue.splice(0);
|
|
1797
|
+
const args = calls.map((call) => call.args);
|
|
1798
|
+
try {
|
|
1799
|
+
const results = await this.callback(args);
|
|
1800
|
+
this.error = false;
|
|
1801
|
+
calls.forEach((call, index) => {
|
|
1802
|
+
const result = results?.[index];
|
|
1803
|
+
if (!Array.isArray(results)) {
|
|
1804
|
+
call.reject(new Error("Callback must return an array."));
|
|
1805
|
+
} else if (calls.length !== results.length) {
|
|
1806
|
+
call.reject(
|
|
1807
|
+
new Error(
|
|
1808
|
+
`Callback must return an array of the same length as the number of provided items. Expected ${calls.length}, but got ${results.length}.`
|
|
1809
|
+
)
|
|
1810
|
+
);
|
|
1811
|
+
} else if (result instanceof Error) {
|
|
1812
|
+
call.reject(result);
|
|
1813
|
+
} else {
|
|
1814
|
+
call.resolve(result);
|
|
1815
|
+
}
|
|
1816
|
+
});
|
|
1817
|
+
} catch (error3) {
|
|
1818
|
+
this.error = true;
|
|
1819
|
+
calls.forEach((call) => {
|
|
1820
|
+
call.reject(error3);
|
|
1821
|
+
});
|
|
1822
|
+
}
|
|
1823
|
+
}
|
|
1824
|
+
get(...args) {
|
|
1825
|
+
const existingCall = this.queue.find(
|
|
1826
|
+
(call2) => stringify(call2.args) === stringify(args)
|
|
1827
|
+
);
|
|
1828
|
+
if (existingCall) {
|
|
1829
|
+
return existingCall.promise;
|
|
1830
|
+
}
|
|
1831
|
+
const call = new BatchCall(args);
|
|
1832
|
+
call.promise = new Promise((resolve, reject) => {
|
|
1833
|
+
call.resolve = resolve;
|
|
1834
|
+
call.reject = reject;
|
|
1835
|
+
});
|
|
1836
|
+
this.queue.push(call);
|
|
1837
|
+
this.schedule();
|
|
1838
|
+
return call.promise;
|
|
1839
|
+
}
|
|
1840
|
+
clear() {
|
|
1841
|
+
this.queue = [];
|
|
1842
|
+
this.error = false;
|
|
1843
|
+
this.clearDelayTimeout();
|
|
1844
|
+
}
|
|
1845
|
+
};
|
|
1846
|
+
function createBatchStore(callback, options) {
|
|
1847
|
+
const batch = new Batch(callback, options);
|
|
1848
|
+
const cache = /* @__PURE__ */ new Map();
|
|
1849
|
+
const eventSource2 = makeEventSource();
|
|
1850
|
+
function getCacheKey(args) {
|
|
1851
|
+
return stringify(args);
|
|
1852
|
+
}
|
|
1853
|
+
function setStateAndNotify(cacheKey, state) {
|
|
1854
|
+
if (state) {
|
|
1855
|
+
cache.set(cacheKey, state);
|
|
1856
|
+
} else {
|
|
1857
|
+
cache.delete(cacheKey);
|
|
1858
|
+
}
|
|
1859
|
+
eventSource2.notify(state);
|
|
1860
|
+
}
|
|
1861
|
+
async function get(...args) {
|
|
1862
|
+
const cacheKey = getCacheKey(args);
|
|
1863
|
+
if (cache.has(cacheKey)) {
|
|
1864
|
+
return;
|
|
1865
|
+
}
|
|
1866
|
+
try {
|
|
1867
|
+
setStateAndNotify(cacheKey, { isLoading: true });
|
|
1868
|
+
const result = await batch.get(...args);
|
|
1869
|
+
setStateAndNotify(cacheKey, { isLoading: false, data: result });
|
|
1870
|
+
} catch (error3) {
|
|
1871
|
+
setStateAndNotify(cacheKey, {
|
|
1872
|
+
isLoading: false,
|
|
1873
|
+
error: error3
|
|
1874
|
+
});
|
|
1875
|
+
}
|
|
1876
|
+
}
|
|
1877
|
+
function getState(...args) {
|
|
1878
|
+
const cacheKey = getCacheKey(args);
|
|
1879
|
+
return cache.get(cacheKey);
|
|
1880
|
+
}
|
|
1881
|
+
return {
|
|
1882
|
+
...eventSource2,
|
|
1883
|
+
get,
|
|
1884
|
+
getState
|
|
1885
|
+
};
|
|
1886
|
+
}
|
|
1887
|
+
|
|
1888
|
+
// src/lib/create-store.ts
|
|
1889
|
+
function createStore(initialState) {
|
|
1890
|
+
let state = initialState;
|
|
1891
|
+
const subscribers = /* @__PURE__ */ new Set();
|
|
1892
|
+
function get() {
|
|
1893
|
+
return state;
|
|
1894
|
+
}
|
|
1895
|
+
function set(callback) {
|
|
1896
|
+
const newState = callback(state);
|
|
1897
|
+
if (state === newState) {
|
|
1898
|
+
return;
|
|
1899
|
+
}
|
|
1900
|
+
state = newState;
|
|
1901
|
+
for (const subscriber of subscribers) {
|
|
1902
|
+
subscriber(state);
|
|
1903
|
+
}
|
|
1904
|
+
}
|
|
1905
|
+
function subscribe(callback) {
|
|
1906
|
+
subscribers.add(callback);
|
|
1907
|
+
callback(state);
|
|
1908
|
+
return () => {
|
|
1909
|
+
subscribers.delete(callback);
|
|
1910
|
+
};
|
|
1911
|
+
}
|
|
1912
|
+
return {
|
|
1913
|
+
get,
|
|
1914
|
+
set,
|
|
1915
|
+
subscribe
|
|
1916
|
+
};
|
|
1917
|
+
}
|
|
1918
|
+
|
|
1714
1919
|
// src/lib/deprecation.ts
|
|
1715
1920
|
var _emittedDeprecationWarnings = /* @__PURE__ */ new Set();
|
|
1716
1921
|
function deprecate(message, key = message) {
|
|
@@ -1744,886 +1949,538 @@ function errorIf(condition, message) {
|
|
|
1744
1949
|
}
|
|
1745
1950
|
}
|
|
1746
1951
|
|
|
1747
|
-
// src/
|
|
1748
|
-
function
|
|
1749
|
-
|
|
1952
|
+
// src/convert-plain-data.ts
|
|
1953
|
+
function convertToCommentData(data) {
|
|
1954
|
+
const editedAt = data.editedAt ? new Date(data.editedAt) : void 0;
|
|
1955
|
+
const createdAt = new Date(data.createdAt);
|
|
1956
|
+
const reactions = data.reactions.map((reaction) => ({
|
|
1957
|
+
...reaction,
|
|
1958
|
+
createdAt: new Date(reaction.createdAt)
|
|
1959
|
+
}));
|
|
1960
|
+
if (data.body) {
|
|
1961
|
+
return {
|
|
1962
|
+
...data,
|
|
1963
|
+
reactions,
|
|
1964
|
+
createdAt,
|
|
1965
|
+
editedAt
|
|
1966
|
+
};
|
|
1967
|
+
} else {
|
|
1968
|
+
const deletedAt = new Date(data.deletedAt);
|
|
1969
|
+
return {
|
|
1970
|
+
...data,
|
|
1971
|
+
reactions,
|
|
1972
|
+
createdAt,
|
|
1973
|
+
editedAt,
|
|
1974
|
+
deletedAt
|
|
1975
|
+
};
|
|
1976
|
+
}
|
|
1750
1977
|
}
|
|
1751
|
-
function
|
|
1752
|
-
|
|
1978
|
+
function convertToThreadData(data) {
|
|
1979
|
+
const updatedAt = data.updatedAt ? new Date(data.updatedAt) : void 0;
|
|
1980
|
+
const createdAt = new Date(data.createdAt);
|
|
1981
|
+
const comments = data.comments.map(
|
|
1982
|
+
(comment) => convertToCommentData(comment)
|
|
1983
|
+
);
|
|
1984
|
+
return {
|
|
1985
|
+
...data,
|
|
1986
|
+
createdAt,
|
|
1987
|
+
updatedAt,
|
|
1988
|
+
comments
|
|
1989
|
+
};
|
|
1753
1990
|
}
|
|
1754
|
-
function
|
|
1755
|
-
return
|
|
1991
|
+
function convertToCommentUserReaction(data) {
|
|
1992
|
+
return {
|
|
1993
|
+
...data,
|
|
1994
|
+
createdAt: new Date(data.createdAt)
|
|
1995
|
+
};
|
|
1756
1996
|
}
|
|
1757
|
-
function
|
|
1758
|
-
|
|
1997
|
+
function convertToInboxNotificationData(data) {
|
|
1998
|
+
const notifiedAt = new Date(data.notifiedAt);
|
|
1999
|
+
const readAt = data.readAt ? new Date(data.readAt) : null;
|
|
2000
|
+
if ("activities" in data) {
|
|
2001
|
+
const activities = data.activities.map((activity) => ({
|
|
2002
|
+
...activity,
|
|
2003
|
+
createdAt: new Date(activity.createdAt)
|
|
2004
|
+
}));
|
|
2005
|
+
return {
|
|
2006
|
+
...data,
|
|
2007
|
+
notifiedAt,
|
|
2008
|
+
readAt,
|
|
2009
|
+
activities
|
|
2010
|
+
};
|
|
2011
|
+
}
|
|
2012
|
+
return {
|
|
2013
|
+
...data,
|
|
2014
|
+
notifiedAt,
|
|
2015
|
+
readAt
|
|
2016
|
+
};
|
|
1759
2017
|
}
|
|
1760
|
-
|
|
1761
|
-
|
|
1762
|
-
|
|
1763
|
-
|
|
1764
|
-
|
|
1765
|
-
};
|
|
1766
|
-
|
|
1767
|
-
|
|
1768
|
-
|
|
1769
|
-
|
|
1770
|
-
|
|
1771
|
-
|
|
1772
|
-
|
|
1773
|
-
|
|
1774
|
-
|
|
2018
|
+
function convertToThreadDeleteInfo(data) {
|
|
2019
|
+
const deletedAt = new Date(data.deletedAt);
|
|
2020
|
+
return {
|
|
2021
|
+
...data,
|
|
2022
|
+
deletedAt
|
|
2023
|
+
};
|
|
2024
|
+
}
|
|
2025
|
+
function convertToInboxNotificationDeleteInfo(data) {
|
|
2026
|
+
const deletedAt = new Date(data.deletedAt);
|
|
2027
|
+
return {
|
|
2028
|
+
...data,
|
|
2029
|
+
deletedAt
|
|
2030
|
+
};
|
|
2031
|
+
}
|
|
2032
|
+
|
|
2033
|
+
// src/lib/url.ts
|
|
2034
|
+
function toURLSearchParams(params) {
|
|
2035
|
+
const result = new URLSearchParams();
|
|
2036
|
+
for (const [key, value] of Object.entries(params)) {
|
|
2037
|
+
if (value !== void 0 && value !== null) {
|
|
2038
|
+
result.set(key, value.toString());
|
|
2039
|
+
}
|
|
1775
2040
|
}
|
|
1776
|
-
|
|
1777
|
-
|
|
1778
|
-
|
|
1779
|
-
const
|
|
1780
|
-
|
|
1781
|
-
|
|
1782
|
-
|
|
1783
|
-
|
|
1784
|
-
|
|
2041
|
+
return result;
|
|
2042
|
+
}
|
|
2043
|
+
function urljoin(baseUrl, path, params) {
|
|
2044
|
+
const url = new URL(path, baseUrl);
|
|
2045
|
+
if (params !== void 0) {
|
|
2046
|
+
url.search = (params instanceof URLSearchParams ? params : toURLSearchParams(params)).toString();
|
|
2047
|
+
}
|
|
2048
|
+
return url.toString();
|
|
2049
|
+
}
|
|
2050
|
+
|
|
2051
|
+
// src/notifications.ts
|
|
2052
|
+
var MARK_INBOX_NOTIFICATIONS_AS_READ_BATCH_DELAY = 50;
|
|
2053
|
+
function createNotificationsApi({
|
|
2054
|
+
baseUrl,
|
|
2055
|
+
authManager,
|
|
2056
|
+
currentUserIdStore,
|
|
2057
|
+
fetcher
|
|
2058
|
+
}) {
|
|
2059
|
+
async function fetchJson(endpoint, options, params) {
|
|
2060
|
+
const authValue = await authManager.getAuthValue({
|
|
2061
|
+
requestedScope: "comments:read"
|
|
2062
|
+
});
|
|
2063
|
+
if (authValue.type === "secret" && authValue.token.parsed.k === "acc" /* ACCESS_TOKEN */) {
|
|
2064
|
+
const userId = authValue.token.parsed.uid;
|
|
2065
|
+
currentUserIdStore.set(() => userId);
|
|
1785
2066
|
}
|
|
1786
|
-
|
|
1787
|
-
|
|
1788
|
-
|
|
1789
|
-
|
|
2067
|
+
const url = urljoin(baseUrl, `/v2/c${endpoint}`, params);
|
|
2068
|
+
const response = await fetcher(url.toString(), {
|
|
2069
|
+
...options,
|
|
2070
|
+
headers: {
|
|
2071
|
+
...options?.headers,
|
|
2072
|
+
Authorization: `Bearer ${getAuthBearerHeaderFromAuthValue(authValue)}`
|
|
2073
|
+
}
|
|
2074
|
+
});
|
|
2075
|
+
if (!response.ok) {
|
|
2076
|
+
if (response.status >= 400 && response.status < 600) {
|
|
2077
|
+
let error3;
|
|
2078
|
+
try {
|
|
2079
|
+
const errorBody = await response.json();
|
|
2080
|
+
error3 = new NotificationsApiError(
|
|
2081
|
+
errorBody.message,
|
|
2082
|
+
response.status,
|
|
2083
|
+
errorBody
|
|
2084
|
+
);
|
|
2085
|
+
} catch {
|
|
2086
|
+
error3 = new NotificationsApiError(
|
|
2087
|
+
response.statusText,
|
|
2088
|
+
response.status
|
|
2089
|
+
);
|
|
1790
2090
|
}
|
|
2091
|
+
throw error3;
|
|
1791
2092
|
}
|
|
1792
2093
|
}
|
|
2094
|
+
let body;
|
|
2095
|
+
try {
|
|
2096
|
+
body = await response.json();
|
|
2097
|
+
} catch {
|
|
2098
|
+
body = {};
|
|
2099
|
+
}
|
|
2100
|
+
return body;
|
|
1793
2101
|
}
|
|
1794
|
-
|
|
1795
|
-
|
|
1796
|
-
|
|
1797
|
-
|
|
1798
|
-
|
|
1799
|
-
|
|
1800
|
-
|
|
1801
|
-
|
|
1802
|
-
|
|
1803
|
-
|
|
1804
|
-
|
|
1805
|
-
|
|
1806
|
-
|
|
1807
|
-
|
|
2102
|
+
async function getInboxNotifications(options) {
|
|
2103
|
+
const json = await fetchJson("/inbox-notifications", void 0, {
|
|
2104
|
+
limit: options?.limit,
|
|
2105
|
+
since: options?.since?.toISOString()
|
|
2106
|
+
});
|
|
2107
|
+
return {
|
|
2108
|
+
threads: json.threads.map((thread) => convertToThreadData(thread)),
|
|
2109
|
+
inboxNotifications: json.inboxNotifications.map(
|
|
2110
|
+
(notification) => convertToInboxNotificationData(notification)
|
|
2111
|
+
),
|
|
2112
|
+
deletedThreads: json.deletedThreads.map(
|
|
2113
|
+
(info) => convertToThreadDeleteInfo(info)
|
|
2114
|
+
),
|
|
2115
|
+
deletedInboxNotifications: json.deletedInboxNotifications.map(
|
|
2116
|
+
(info) => convertToInboxNotificationDeleteInfo(info)
|
|
2117
|
+
),
|
|
2118
|
+
meta: {
|
|
2119
|
+
requestedAt: new Date(json.meta.requestedAt)
|
|
2120
|
+
}
|
|
2121
|
+
};
|
|
1808
2122
|
}
|
|
1809
|
-
|
|
1810
|
-
|
|
1811
|
-
|
|
1812
|
-
});
|
|
1813
|
-
for (const [index, userId] of userIds.entries()) {
|
|
1814
|
-
const user = users?.[index];
|
|
1815
|
-
if (user) {
|
|
1816
|
-
resolvedUsers.set(userId, user);
|
|
1817
|
-
}
|
|
2123
|
+
async function getUnreadInboxNotificationsCount() {
|
|
2124
|
+
const { count } = await fetchJson("/inbox-notifications/count");
|
|
2125
|
+
return count;
|
|
1818
2126
|
}
|
|
1819
|
-
|
|
1820
|
-
|
|
1821
|
-
|
|
1822
|
-
|
|
1823
|
-
|
|
1824
|
-
|
|
1825
|
-
|
|
1826
|
-
|
|
1827
|
-
};
|
|
1828
|
-
var htmlEscapablesRegex = new RegExp(
|
|
1829
|
-
Object.keys(htmlEscapables).map((entity) => `\\${entity}`).join("|"),
|
|
1830
|
-
"g"
|
|
1831
|
-
);
|
|
1832
|
-
function htmlSafe(value) {
|
|
1833
|
-
return new HtmlSafeString([String(value)], []);
|
|
1834
|
-
}
|
|
1835
|
-
function joinHtml(strings) {
|
|
1836
|
-
if (strings.length <= 0) {
|
|
1837
|
-
return new HtmlSafeString([""], []);
|
|
2127
|
+
async function markAllInboxNotificationsAsRead() {
|
|
2128
|
+
await fetchJson("/inbox-notifications/read", {
|
|
2129
|
+
method: "POST",
|
|
2130
|
+
headers: {
|
|
2131
|
+
"Content-Type": "application/json"
|
|
2132
|
+
},
|
|
2133
|
+
body: JSON.stringify({ inboxNotificationIds: "all" })
|
|
2134
|
+
});
|
|
1838
2135
|
}
|
|
1839
|
-
|
|
1840
|
-
|
|
1841
|
-
|
|
2136
|
+
async function markInboxNotificationsAsRead(inboxNotificationIds) {
|
|
2137
|
+
await fetchJson("/inbox-notifications/read", {
|
|
2138
|
+
method: "POST",
|
|
2139
|
+
headers: {
|
|
2140
|
+
"Content-Type": "application/json"
|
|
2141
|
+
},
|
|
2142
|
+
body: JSON.stringify({ inboxNotificationIds })
|
|
2143
|
+
});
|
|
2144
|
+
}
|
|
2145
|
+
const batchedMarkInboxNotificationsAsRead = new Batch(
|
|
2146
|
+
async (batchedInboxNotificationIds) => {
|
|
2147
|
+
const inboxNotificationIds = batchedInboxNotificationIds.flat();
|
|
2148
|
+
await markInboxNotificationsAsRead(inboxNotificationIds);
|
|
2149
|
+
return inboxNotificationIds;
|
|
2150
|
+
},
|
|
2151
|
+
{ delay: MARK_INBOX_NOTIFICATIONS_AS_READ_BATCH_DELAY }
|
|
1842
2152
|
);
|
|
1843
|
-
|
|
1844
|
-
|
|
1845
|
-
if (value instanceof HtmlSafeString) {
|
|
1846
|
-
return value.toString();
|
|
2153
|
+
async function markInboxNotificationAsRead(inboxNotificationId) {
|
|
2154
|
+
await batchedMarkInboxNotificationsAsRead.get(inboxNotificationId);
|
|
1847
2155
|
}
|
|
1848
|
-
|
|
1849
|
-
|
|
2156
|
+
return {
|
|
2157
|
+
getInboxNotifications,
|
|
2158
|
+
getUnreadInboxNotificationsCount,
|
|
2159
|
+
markAllInboxNotificationsAsRead,
|
|
2160
|
+
markInboxNotificationAsRead
|
|
2161
|
+
};
|
|
2162
|
+
}
|
|
2163
|
+
|
|
2164
|
+
// src/lib/position.ts
|
|
2165
|
+
var MIN_CODE = 32;
|
|
2166
|
+
var MAX_CODE = 126;
|
|
2167
|
+
var NUM_DIGITS = MAX_CODE - MIN_CODE + 1;
|
|
2168
|
+
var ZERO = nthDigit(0);
|
|
2169
|
+
var ONE = nthDigit(1);
|
|
2170
|
+
var ZERO_NINE = ZERO + nthDigit(-1);
|
|
2171
|
+
function nthDigit(n) {
|
|
2172
|
+
const code = MIN_CODE + (n < 0 ? NUM_DIGITS + n : n);
|
|
2173
|
+
if (code < MIN_CODE || code > MAX_CODE) {
|
|
2174
|
+
throw new Error(`Invalid n value: ${n}`);
|
|
1850
2175
|
}
|
|
1851
|
-
return String(
|
|
1852
|
-
htmlEscapablesRegex,
|
|
1853
|
-
(character) => htmlEscapables[character]
|
|
1854
|
-
);
|
|
2176
|
+
return String.fromCharCode(code);
|
|
1855
2177
|
}
|
|
1856
|
-
|
|
1857
|
-
|
|
1858
|
-
|
|
1859
|
-
|
|
2178
|
+
function makePosition(x, y) {
|
|
2179
|
+
if (x !== void 0 && y !== void 0) {
|
|
2180
|
+
return between(x, y);
|
|
2181
|
+
} else if (x !== void 0) {
|
|
2182
|
+
return after(x);
|
|
2183
|
+
} else if (y !== void 0) {
|
|
2184
|
+
return before(y);
|
|
2185
|
+
} else {
|
|
2186
|
+
return ONE;
|
|
1860
2187
|
}
|
|
1861
|
-
|
|
1862
|
-
|
|
1863
|
-
|
|
1864
|
-
|
|
2188
|
+
}
|
|
2189
|
+
function before(pos) {
|
|
2190
|
+
const lastIndex = pos.length - 1;
|
|
2191
|
+
for (let i = 0; i <= lastIndex; i++) {
|
|
2192
|
+
const code = pos.charCodeAt(i);
|
|
2193
|
+
if (code <= MIN_CODE) {
|
|
2194
|
+
continue;
|
|
2195
|
+
}
|
|
2196
|
+
if (i === lastIndex) {
|
|
2197
|
+
if (code === MIN_CODE + 1) {
|
|
2198
|
+
return pos.substring(0, i) + ZERO_NINE;
|
|
2199
|
+
} else {
|
|
2200
|
+
return pos.substring(0, i) + String.fromCharCode(code - 1);
|
|
2201
|
+
}
|
|
2202
|
+
} else {
|
|
2203
|
+
return pos.substring(0, i + 1);
|
|
2204
|
+
}
|
|
1865
2205
|
}
|
|
1866
|
-
|
|
1867
|
-
function html(strings, ...values) {
|
|
1868
|
-
return new HtmlSafeString(strings, values);
|
|
2206
|
+
return ONE;
|
|
1869
2207
|
}
|
|
1870
|
-
|
|
1871
|
-
|
|
1872
|
-
|
|
1873
|
-
|
|
1874
|
-
|
|
1875
|
-
|
|
1876
|
-
|
|
1877
|
-
"|": "\\|",
|
|
1878
|
-
"(": "\\(",
|
|
1879
|
-
")": "\\)",
|
|
1880
|
-
"{": "\\{",
|
|
1881
|
-
"}": "\\}",
|
|
1882
|
-
"[": "\\[",
|
|
1883
|
-
"]": "\\]"
|
|
1884
|
-
};
|
|
1885
|
-
var markdownEscapablesRegex = new RegExp(
|
|
1886
|
-
Object.keys(markdownEscapables).map((entity) => `\\${entity}`).join("|"),
|
|
1887
|
-
"g"
|
|
1888
|
-
);
|
|
1889
|
-
function joinMarkdown(strings) {
|
|
1890
|
-
if (strings.length <= 0) {
|
|
1891
|
-
return new MarkdownSafeString([""], []);
|
|
2208
|
+
function after(pos) {
|
|
2209
|
+
for (let i = 0; i <= pos.length - 1; i++) {
|
|
2210
|
+
const code = pos.charCodeAt(i);
|
|
2211
|
+
if (code >= MAX_CODE) {
|
|
2212
|
+
continue;
|
|
2213
|
+
}
|
|
2214
|
+
return pos.substring(0, i) + String.fromCharCode(code + 1);
|
|
1892
2215
|
}
|
|
1893
|
-
return
|
|
1894
|
-
["", ...Array(strings.length - 1).fill(""), ""],
|
|
1895
|
-
strings
|
|
1896
|
-
);
|
|
2216
|
+
return pos + ONE;
|
|
1897
2217
|
}
|
|
1898
|
-
function
|
|
1899
|
-
if (
|
|
1900
|
-
return
|
|
2218
|
+
function between(lo, hi) {
|
|
2219
|
+
if (lo < hi) {
|
|
2220
|
+
return _between(lo, hi);
|
|
2221
|
+
} else if (lo > hi) {
|
|
2222
|
+
return _between(hi, lo);
|
|
2223
|
+
} else {
|
|
2224
|
+
throw new Error("Cannot compute value between two equal positions");
|
|
1901
2225
|
}
|
|
1902
|
-
|
|
1903
|
-
|
|
2226
|
+
}
|
|
2227
|
+
function _between(lo, hi) {
|
|
2228
|
+
let index = 0;
|
|
2229
|
+
const loLen = lo.length;
|
|
2230
|
+
const hiLen = hi.length;
|
|
2231
|
+
while (true) {
|
|
2232
|
+
const loCode = index < loLen ? lo.charCodeAt(index) : MIN_CODE;
|
|
2233
|
+
const hiCode = index < hiLen ? hi.charCodeAt(index) : MAX_CODE;
|
|
2234
|
+
if (loCode === hiCode) {
|
|
2235
|
+
index++;
|
|
2236
|
+
continue;
|
|
2237
|
+
}
|
|
2238
|
+
if (hiCode - loCode === 1) {
|
|
2239
|
+
const size = index + 1;
|
|
2240
|
+
let prefix = lo.substring(0, size);
|
|
2241
|
+
if (prefix.length < size) {
|
|
2242
|
+
prefix += ZERO.repeat(size - prefix.length);
|
|
2243
|
+
}
|
|
2244
|
+
const suffix = lo.substring(size);
|
|
2245
|
+
const nines = "";
|
|
2246
|
+
return prefix + _between(suffix, nines);
|
|
2247
|
+
} else {
|
|
2248
|
+
return takeN(lo, index) + String.fromCharCode(hiCode + loCode >> 1);
|
|
2249
|
+
}
|
|
1904
2250
|
}
|
|
1905
|
-
return String(value).replace(
|
|
1906
|
-
markdownEscapablesRegex,
|
|
1907
|
-
(character) => markdownEscapables[character]
|
|
1908
|
-
);
|
|
1909
2251
|
}
|
|
1910
|
-
|
|
1911
|
-
|
|
1912
|
-
|
|
1913
|
-
|
|
2252
|
+
function takeN(pos, n) {
|
|
2253
|
+
return n < pos.length ? pos.substring(0, n) : pos + ZERO.repeat(n - pos.length);
|
|
2254
|
+
}
|
|
2255
|
+
var MIN_NON_ZERO_CODE = MIN_CODE + 1;
|
|
2256
|
+
function isPos(str) {
|
|
2257
|
+
if (str === "") {
|
|
2258
|
+
return false;
|
|
1914
2259
|
}
|
|
1915
|
-
|
|
1916
|
-
|
|
1917
|
-
|
|
1918
|
-
|
|
2260
|
+
const lastIdx = str.length - 1;
|
|
2261
|
+
const last = str.charCodeAt(lastIdx);
|
|
2262
|
+
if (last < MIN_NON_ZERO_CODE || last > MAX_CODE) {
|
|
2263
|
+
return false;
|
|
1919
2264
|
}
|
|
1920
|
-
|
|
1921
|
-
|
|
1922
|
-
|
|
1923
|
-
|
|
1924
|
-
|
|
1925
|
-
if (url.startsWith("http://") || url.startsWith("https://")) {
|
|
1926
|
-
return url;
|
|
1927
|
-
} else if (url.startsWith("www.")) {
|
|
1928
|
-
return "https://" + url;
|
|
2265
|
+
for (let i = 0; i < lastIdx; i++) {
|
|
2266
|
+
const code = str.charCodeAt(i);
|
|
2267
|
+
if (code < MIN_CODE || code > MAX_CODE) {
|
|
2268
|
+
return false;
|
|
2269
|
+
}
|
|
1929
2270
|
}
|
|
1930
|
-
return;
|
|
2271
|
+
return true;
|
|
1931
2272
|
}
|
|
1932
|
-
|
|
1933
|
-
|
|
1934
|
-
|
|
1935
|
-
|
|
1936
|
-
|
|
1937
|
-
return `@${user?.name ?? element.id}`;
|
|
2273
|
+
function convertToPos(str) {
|
|
2274
|
+
const codes = [];
|
|
2275
|
+
for (let i = 0; i < str.length; i++) {
|
|
2276
|
+
const code = str.charCodeAt(i);
|
|
2277
|
+
codes.push(code < MIN_CODE ? MIN_CODE : code > MAX_CODE ? MAX_CODE : code);
|
|
1938
2278
|
}
|
|
1939
|
-
|
|
1940
|
-
|
|
1941
|
-
paragraph: ({ children }) => {
|
|
1942
|
-
return children ? html`<p>${htmlSafe(children)}</p>` : children;
|
|
1943
|
-
},
|
|
1944
|
-
text: ({ element }) => {
|
|
1945
|
-
let children = element.text;
|
|
1946
|
-
if (!children) {
|
|
1947
|
-
return children;
|
|
1948
|
-
}
|
|
1949
|
-
if (element.bold) {
|
|
1950
|
-
children = html`<strong>${children}</strong>`;
|
|
1951
|
-
}
|
|
1952
|
-
if (element.italic) {
|
|
1953
|
-
children = html`<em>${children}</em>`;
|
|
1954
|
-
}
|
|
1955
|
-
if (element.strikethrough) {
|
|
1956
|
-
children = html`<s>${children}</s>`;
|
|
1957
|
-
}
|
|
1958
|
-
if (element.code) {
|
|
1959
|
-
children = html`<code>${children}</code>`;
|
|
1960
|
-
}
|
|
1961
|
-
return children;
|
|
1962
|
-
},
|
|
1963
|
-
link: ({ element, href }) => {
|
|
1964
|
-
return html`<a href="${href}" target="_blank" rel="noopener noreferrer">${element.url}</a>`;
|
|
1965
|
-
},
|
|
1966
|
-
mention: ({ element, user }) => {
|
|
1967
|
-
return html`<span data-mention>@${user?.name ?? element.id}</span>`;
|
|
2279
|
+
while (codes.length > 0 && codes[codes.length - 1] === MIN_CODE) {
|
|
2280
|
+
codes.length--;
|
|
1968
2281
|
}
|
|
1969
|
-
|
|
1970
|
-
|
|
1971
|
-
|
|
1972
|
-
return children;
|
|
1973
|
-
},
|
|
1974
|
-
text: ({ element }) => {
|
|
1975
|
-
let children = element.text;
|
|
1976
|
-
if (!children) {
|
|
1977
|
-
return children;
|
|
1978
|
-
}
|
|
1979
|
-
if (element.bold) {
|
|
1980
|
-
children = markdown`**${children}**`;
|
|
1981
|
-
}
|
|
1982
|
-
if (element.italic) {
|
|
1983
|
-
children = markdown`_${children}_`;
|
|
1984
|
-
}
|
|
1985
|
-
if (element.strikethrough) {
|
|
1986
|
-
children = markdown`~~${children}~~`;
|
|
1987
|
-
}
|
|
1988
|
-
if (element.code) {
|
|
1989
|
-
children = markdown`\`${children}\``;
|
|
1990
|
-
}
|
|
1991
|
-
return children;
|
|
1992
|
-
},
|
|
1993
|
-
link: ({ element, href }) => {
|
|
1994
|
-
return markdown`[${element.url}](${href})`;
|
|
1995
|
-
},
|
|
1996
|
-
mention: ({ element, user }) => {
|
|
1997
|
-
return markdown`@${user?.name ?? element.id}`;
|
|
1998
|
-
}
|
|
1999
|
-
};
|
|
2000
|
-
async function stringifyCommentBody(body, options) {
|
|
2001
|
-
const format = options?.format ?? "plain";
|
|
2002
|
-
const separator = options?.separator ?? (format === "markdown" ? "\n\n" : "\n");
|
|
2003
|
-
const elements = {
|
|
2004
|
-
...format === "html" ? stringifyCommentBodyHtmlElements : format === "markdown" ? stringifyCommentBodyMarkdownElements : stringifyCommentBodyPlainElements,
|
|
2005
|
-
...options?.elements
|
|
2006
|
-
};
|
|
2007
|
-
const resolvedUsers = await resolveUsersInCommentBody(
|
|
2008
|
-
body,
|
|
2009
|
-
options?.resolveUsers
|
|
2282
|
+
return codes.length > 0 ? String.fromCharCode(...codes) : (
|
|
2283
|
+
// Edge case: the str was a 0-only string, which is invalid. Default back to .1
|
|
2284
|
+
ONE
|
|
2010
2285
|
);
|
|
2011
|
-
const blocks = body.content.flatMap((block, blockIndex) => {
|
|
2012
|
-
switch (block.type) {
|
|
2013
|
-
case "paragraph": {
|
|
2014
|
-
const inlines = block.children.flatMap((inline, inlineIndex) => {
|
|
2015
|
-
if (isCommentBodyMention(inline)) {
|
|
2016
|
-
return inline.id ? [
|
|
2017
|
-
elements.mention(
|
|
2018
|
-
{
|
|
2019
|
-
element: inline,
|
|
2020
|
-
user: resolvedUsers.get(inline.id)
|
|
2021
|
-
},
|
|
2022
|
-
inlineIndex
|
|
2023
|
-
)
|
|
2024
|
-
] : [];
|
|
2025
|
-
}
|
|
2026
|
-
if (isCommentBodyLink(inline)) {
|
|
2027
|
-
return [
|
|
2028
|
-
elements.link(
|
|
2029
|
-
{
|
|
2030
|
-
element: inline,
|
|
2031
|
-
href: toAbsoluteUrl(inline.url) ?? inline.url
|
|
2032
|
-
},
|
|
2033
|
-
inlineIndex
|
|
2034
|
-
)
|
|
2035
|
-
];
|
|
2036
|
-
}
|
|
2037
|
-
if (isCommentBodyText(inline)) {
|
|
2038
|
-
return [elements.text({ element: inline }, inlineIndex)];
|
|
2039
|
-
}
|
|
2040
|
-
return [];
|
|
2041
|
-
});
|
|
2042
|
-
return [
|
|
2043
|
-
elements.paragraph(
|
|
2044
|
-
{ element: block, children: inlines.join("") },
|
|
2045
|
-
blockIndex
|
|
2046
|
-
)
|
|
2047
|
-
];
|
|
2048
|
-
}
|
|
2049
|
-
default:
|
|
2050
|
-
return [];
|
|
2051
|
-
}
|
|
2052
|
-
});
|
|
2053
|
-
return blocks.join(separator);
|
|
2054
2286
|
}
|
|
2055
|
-
function
|
|
2056
|
-
|
|
2057
|
-
const createdAt = new Date(data.createdAt);
|
|
2058
|
-
const reactions = data.reactions.map((reaction) => ({
|
|
2059
|
-
...reaction,
|
|
2060
|
-
createdAt: new Date(reaction.createdAt)
|
|
2061
|
-
}));
|
|
2062
|
-
if (data.body) {
|
|
2063
|
-
return {
|
|
2064
|
-
...data,
|
|
2065
|
-
reactions,
|
|
2066
|
-
createdAt,
|
|
2067
|
-
editedAt
|
|
2068
|
-
};
|
|
2069
|
-
} else {
|
|
2070
|
-
const deletedAt = new Date(data.deletedAt);
|
|
2071
|
-
return {
|
|
2072
|
-
...data,
|
|
2073
|
-
reactions,
|
|
2074
|
-
createdAt,
|
|
2075
|
-
editedAt,
|
|
2076
|
-
deletedAt
|
|
2077
|
-
};
|
|
2078
|
-
}
|
|
2287
|
+
function asPos(str) {
|
|
2288
|
+
return isPos(str) ? str : convertToPos(str);
|
|
2079
2289
|
}
|
|
2080
|
-
|
|
2081
|
-
|
|
2082
|
-
|
|
2083
|
-
|
|
2084
|
-
|
|
2085
|
-
|
|
2290
|
+
|
|
2291
|
+
// src/protocol/Op.ts
|
|
2292
|
+
var OpCode = /* @__PURE__ */ ((OpCode2) => {
|
|
2293
|
+
OpCode2[OpCode2["INIT"] = 0] = "INIT";
|
|
2294
|
+
OpCode2[OpCode2["SET_PARENT_KEY"] = 1] = "SET_PARENT_KEY";
|
|
2295
|
+
OpCode2[OpCode2["CREATE_LIST"] = 2] = "CREATE_LIST";
|
|
2296
|
+
OpCode2[OpCode2["UPDATE_OBJECT"] = 3] = "UPDATE_OBJECT";
|
|
2297
|
+
OpCode2[OpCode2["CREATE_OBJECT"] = 4] = "CREATE_OBJECT";
|
|
2298
|
+
OpCode2[OpCode2["DELETE_CRDT"] = 5] = "DELETE_CRDT";
|
|
2299
|
+
OpCode2[OpCode2["DELETE_OBJECT_KEY"] = 6] = "DELETE_OBJECT_KEY";
|
|
2300
|
+
OpCode2[OpCode2["CREATE_MAP"] = 7] = "CREATE_MAP";
|
|
2301
|
+
OpCode2[OpCode2["CREATE_REGISTER"] = 8] = "CREATE_REGISTER";
|
|
2302
|
+
return OpCode2;
|
|
2303
|
+
})(OpCode || {});
|
|
2304
|
+
function ackOp(opId) {
|
|
2086
2305
|
return {
|
|
2087
|
-
|
|
2088
|
-
|
|
2089
|
-
|
|
2090
|
-
|
|
2306
|
+
type: 5 /* DELETE_CRDT */,
|
|
2307
|
+
id: "ACK",
|
|
2308
|
+
// (H)ACK
|
|
2309
|
+
opId
|
|
2091
2310
|
};
|
|
2092
2311
|
}
|
|
2093
|
-
function
|
|
2094
|
-
return
|
|
2095
|
-
...data,
|
|
2096
|
-
createdAt: new Date(data.createdAt)
|
|
2097
|
-
};
|
|
2312
|
+
function isAckOp(op) {
|
|
2313
|
+
return op.type === 5 /* DELETE_CRDT */ && op.id === "ACK";
|
|
2098
2314
|
}
|
|
2099
2315
|
|
|
2100
|
-
// src/
|
|
2101
|
-
function
|
|
2102
|
-
|
|
2103
|
-
return authValue.publicApiKey;
|
|
2104
|
-
} else {
|
|
2105
|
-
return authValue.token.raw;
|
|
2106
|
-
}
|
|
2316
|
+
// src/crdts/AbstractCrdt.ts
|
|
2317
|
+
function crdtAsLiveNode(value) {
|
|
2318
|
+
return value;
|
|
2107
2319
|
}
|
|
2108
|
-
|
|
2109
|
-
|
|
2110
|
-
|
|
2111
|
-
|
|
2112
|
-
|
|
2113
|
-
|
|
2320
|
+
function HasParent(node, key, pos = asPos(key)) {
|
|
2321
|
+
return Object.freeze({ type: "HasParent", node, key, pos });
|
|
2322
|
+
}
|
|
2323
|
+
var NoParent = Object.freeze({ type: "NoParent" });
|
|
2324
|
+
function Orphaned(oldKey, oldPos = asPos(oldKey)) {
|
|
2325
|
+
return Object.freeze({ type: "Orphaned", oldKey, oldPos });
|
|
2326
|
+
}
|
|
2327
|
+
var AbstractCrdt = class {
|
|
2328
|
+
constructor() {
|
|
2329
|
+
/** @internal */
|
|
2330
|
+
this._parent = NoParent;
|
|
2114
2331
|
}
|
|
2115
|
-
|
|
2116
|
-
|
|
2117
|
-
|
|
2118
|
-
|
|
2119
|
-
|
|
2120
|
-
|
|
2121
|
-
|
|
2122
|
-
|
|
2123
|
-
|
|
2124
|
-
|
|
2125
|
-
|
|
2126
|
-
response.status,
|
|
2127
|
-
errorBody
|
|
2128
|
-
);
|
|
2129
|
-
} catch {
|
|
2130
|
-
error3 = new CommentsApiError(response.statusText, response.status);
|
|
2131
|
-
}
|
|
2132
|
-
throw error3;
|
|
2133
|
-
}
|
|
2332
|
+
/** @internal */
|
|
2333
|
+
_getParentKeyOrThrow() {
|
|
2334
|
+
switch (this.parent.type) {
|
|
2335
|
+
case "HasParent":
|
|
2336
|
+
return this.parent.key;
|
|
2337
|
+
case "NoParent":
|
|
2338
|
+
throw new Error("Parent key is missing");
|
|
2339
|
+
case "Orphaned":
|
|
2340
|
+
return this.parent.oldKey;
|
|
2341
|
+
default:
|
|
2342
|
+
return assertNever(this.parent, "Unknown state");
|
|
2134
2343
|
}
|
|
2135
|
-
|
|
2136
|
-
|
|
2137
|
-
|
|
2138
|
-
|
|
2139
|
-
|
|
2344
|
+
}
|
|
2345
|
+
/** @internal */
|
|
2346
|
+
get _parentPos() {
|
|
2347
|
+
switch (this.parent.type) {
|
|
2348
|
+
case "HasParent":
|
|
2349
|
+
return this.parent.pos;
|
|
2350
|
+
case "NoParent":
|
|
2351
|
+
throw new Error("Parent key is missing");
|
|
2352
|
+
case "Orphaned":
|
|
2353
|
+
return this.parent.oldPos;
|
|
2354
|
+
default:
|
|
2355
|
+
return assertNever(this.parent, "Unknown state");
|
|
2140
2356
|
}
|
|
2141
|
-
return body;
|
|
2142
2357
|
}
|
|
2143
|
-
|
|
2144
|
-
|
|
2145
|
-
|
|
2146
|
-
`/v2/c/rooms/${encodeURIComponent(roomId2)}${endpoint}`,
|
|
2147
|
-
config.baseUrl
|
|
2148
|
-
);
|
|
2149
|
-
return await fetch(url.toString(), {
|
|
2150
|
-
...options,
|
|
2151
|
-
headers: {
|
|
2152
|
-
...options?.headers,
|
|
2153
|
-
Authorization: `Bearer ${getAuthBearerHeaderFromAuthValue(authValue)}`
|
|
2154
|
-
}
|
|
2155
|
-
});
|
|
2358
|
+
/** @internal */
|
|
2359
|
+
get _pool() {
|
|
2360
|
+
return this.__pool;
|
|
2156
2361
|
}
|
|
2157
|
-
|
|
2158
|
-
|
|
2159
|
-
body: JSON.stringify({
|
|
2160
|
-
...options?.query?.metadata && { metadata: options.query.metadata }
|
|
2161
|
-
}),
|
|
2162
|
-
headers: {
|
|
2163
|
-
"Content-Type": "application/json"
|
|
2164
|
-
},
|
|
2165
|
-
method: "POST"
|
|
2166
|
-
});
|
|
2167
|
-
if (response.ok) {
|
|
2168
|
-
const json = await response.json();
|
|
2169
|
-
return json.data.map((thread) => convertToThreadData(thread));
|
|
2170
|
-
} else if (response.status === 404) {
|
|
2171
|
-
return [];
|
|
2172
|
-
} else {
|
|
2173
|
-
throw new Error("There was an error while getting threads.");
|
|
2174
|
-
}
|
|
2362
|
+
get roomId() {
|
|
2363
|
+
return this.__pool ? this.__pool.roomId : null;
|
|
2175
2364
|
}
|
|
2176
|
-
|
|
2177
|
-
|
|
2178
|
-
|
|
2179
|
-
commentId,
|
|
2180
|
-
threadId
|
|
2181
|
-
}) {
|
|
2182
|
-
const thread = await fetchJson(
|
|
2183
|
-
"/threads",
|
|
2184
|
-
{
|
|
2185
|
-
method: "POST",
|
|
2186
|
-
headers: {
|
|
2187
|
-
"Content-Type": "application/json"
|
|
2188
|
-
},
|
|
2189
|
-
body: JSON.stringify({
|
|
2190
|
-
id: threadId,
|
|
2191
|
-
comment: {
|
|
2192
|
-
id: commentId,
|
|
2193
|
-
body
|
|
2194
|
-
},
|
|
2195
|
-
metadata
|
|
2196
|
-
})
|
|
2197
|
-
}
|
|
2198
|
-
);
|
|
2199
|
-
return convertToThreadData(thread);
|
|
2365
|
+
/** @internal */
|
|
2366
|
+
get _id() {
|
|
2367
|
+
return this.__id;
|
|
2200
2368
|
}
|
|
2201
|
-
|
|
2202
|
-
|
|
2203
|
-
|
|
2204
|
-
}) {
|
|
2205
|
-
return await fetchJson(
|
|
2206
|
-
`/threads/${encodeURIComponent(threadId)}/metadata`,
|
|
2207
|
-
{
|
|
2208
|
-
method: "POST",
|
|
2209
|
-
headers: {
|
|
2210
|
-
"Content-Type": "application/json"
|
|
2211
|
-
},
|
|
2212
|
-
body: JSON.stringify(metadata)
|
|
2213
|
-
}
|
|
2214
|
-
);
|
|
2369
|
+
/** @internal */
|
|
2370
|
+
get parent() {
|
|
2371
|
+
return this._parent;
|
|
2215
2372
|
}
|
|
2216
|
-
|
|
2217
|
-
|
|
2218
|
-
|
|
2219
|
-
|
|
2220
|
-
|
|
2221
|
-
|
|
2222
|
-
|
|
2223
|
-
|
|
2224
|
-
|
|
2225
|
-
|
|
2226
|
-
|
|
2227
|
-
|
|
2228
|
-
body: JSON.stringify({
|
|
2229
|
-
id: commentId,
|
|
2230
|
-
body
|
|
2231
|
-
})
|
|
2232
|
-
}
|
|
2233
|
-
);
|
|
2234
|
-
return convertToCommentData(comment);
|
|
2373
|
+
/** @internal */
|
|
2374
|
+
get _parentKey() {
|
|
2375
|
+
switch (this.parent.type) {
|
|
2376
|
+
case "HasParent":
|
|
2377
|
+
return this.parent.key;
|
|
2378
|
+
case "NoParent":
|
|
2379
|
+
return null;
|
|
2380
|
+
case "Orphaned":
|
|
2381
|
+
return this.parent.oldKey;
|
|
2382
|
+
default:
|
|
2383
|
+
return assertNever(this.parent, "Unknown state");
|
|
2384
|
+
}
|
|
2235
2385
|
}
|
|
2236
|
-
|
|
2237
|
-
|
|
2238
|
-
|
|
2239
|
-
|
|
2240
|
-
|
|
2241
|
-
|
|
2242
|
-
|
|
2243
|
-
|
|
2244
|
-
)}`,
|
|
2245
|
-
{
|
|
2246
|
-
method: "POST",
|
|
2247
|
-
headers: {
|
|
2248
|
-
"Content-Type": "application/json"
|
|
2249
|
-
},
|
|
2250
|
-
body: JSON.stringify({
|
|
2251
|
-
body
|
|
2252
|
-
})
|
|
2386
|
+
/** @internal */
|
|
2387
|
+
_apply(op, _isLocal) {
|
|
2388
|
+
switch (op.type) {
|
|
2389
|
+
case 5 /* DELETE_CRDT */: {
|
|
2390
|
+
if (this.parent.type === "HasParent") {
|
|
2391
|
+
return this.parent.node._detachChild(crdtAsLiveNode(this));
|
|
2392
|
+
}
|
|
2393
|
+
return { modified: false };
|
|
2253
2394
|
}
|
|
2254
|
-
|
|
2255
|
-
return
|
|
2395
|
+
}
|
|
2396
|
+
return { modified: false };
|
|
2256
2397
|
}
|
|
2257
|
-
|
|
2258
|
-
|
|
2259
|
-
|
|
2260
|
-
|
|
2261
|
-
|
|
2262
|
-
|
|
2263
|
-
|
|
2264
|
-
|
|
2265
|
-
|
|
2266
|
-
|
|
2398
|
+
/** @internal */
|
|
2399
|
+
_setParentLink(newParentNode, newParentKey) {
|
|
2400
|
+
switch (this.parent.type) {
|
|
2401
|
+
case "HasParent":
|
|
2402
|
+
if (this.parent.node !== newParentNode) {
|
|
2403
|
+
throw new Error("Cannot set parent: node already has a parent");
|
|
2404
|
+
} else {
|
|
2405
|
+
this._parent = HasParent(newParentNode, newParentKey);
|
|
2406
|
+
return;
|
|
2407
|
+
}
|
|
2408
|
+
case "Orphaned":
|
|
2409
|
+
case "NoParent": {
|
|
2410
|
+
this._parent = HasParent(newParentNode, newParentKey);
|
|
2411
|
+
return;
|
|
2267
2412
|
}
|
|
2268
|
-
|
|
2413
|
+
default:
|
|
2414
|
+
return assertNever(this.parent, "Unknown state");
|
|
2415
|
+
}
|
|
2269
2416
|
}
|
|
2270
|
-
|
|
2271
|
-
|
|
2272
|
-
|
|
2273
|
-
|
|
2274
|
-
|
|
2275
|
-
|
|
2276
|
-
|
|
2277
|
-
|
|
2278
|
-
)}/reactions`,
|
|
2279
|
-
{
|
|
2280
|
-
method: "POST",
|
|
2281
|
-
headers: {
|
|
2282
|
-
"Content-Type": "application/json"
|
|
2283
|
-
},
|
|
2284
|
-
body: JSON.stringify({ emoji })
|
|
2285
|
-
}
|
|
2286
|
-
);
|
|
2287
|
-
return convertToCommentUserReaction(reaction);
|
|
2417
|
+
/** @internal */
|
|
2418
|
+
_attach(id, pool) {
|
|
2419
|
+
if (this.__id || this.__pool) {
|
|
2420
|
+
throw new Error("Cannot attach node: already attached");
|
|
2421
|
+
}
|
|
2422
|
+
pool.addNode(id, crdtAsLiveNode(this));
|
|
2423
|
+
this.__id = id;
|
|
2424
|
+
this.__pool = pool;
|
|
2288
2425
|
}
|
|
2289
|
-
|
|
2290
|
-
|
|
2291
|
-
|
|
2292
|
-
|
|
2293
|
-
|
|
2294
|
-
|
|
2295
|
-
|
|
2296
|
-
|
|
2297
|
-
|
|
2298
|
-
{
|
|
2299
|
-
method: "DELETE"
|
|
2426
|
+
/** @internal */
|
|
2427
|
+
_detach() {
|
|
2428
|
+
if (this.__pool && this.__id) {
|
|
2429
|
+
this.__pool.deleteNode(this.__id);
|
|
2430
|
+
}
|
|
2431
|
+
switch (this.parent.type) {
|
|
2432
|
+
case "HasParent": {
|
|
2433
|
+
this._parent = Orphaned(this.parent.key, this.parent.pos);
|
|
2434
|
+
break;
|
|
2300
2435
|
}
|
|
2301
|
-
|
|
2302
|
-
|
|
2303
|
-
|
|
2304
|
-
|
|
2305
|
-
|
|
2306
|
-
|
|
2307
|
-
|
|
2308
|
-
|
|
2309
|
-
|
|
2310
|
-
addReaction,
|
|
2311
|
-
removeReaction
|
|
2312
|
-
};
|
|
2313
|
-
}
|
|
2314
|
-
|
|
2315
|
-
// src/lib/position.ts
|
|
2316
|
-
var MIN_CODE = 32;
|
|
2317
|
-
var MAX_CODE = 126;
|
|
2318
|
-
var NUM_DIGITS = MAX_CODE - MIN_CODE + 1;
|
|
2319
|
-
var ZERO = nthDigit(0);
|
|
2320
|
-
var ONE = nthDigit(1);
|
|
2321
|
-
var ZERO_NINE = ZERO + nthDigit(-1);
|
|
2322
|
-
function nthDigit(n) {
|
|
2323
|
-
const code = MIN_CODE + (n < 0 ? NUM_DIGITS + n : n);
|
|
2324
|
-
if (code < MIN_CODE || code > MAX_CODE) {
|
|
2325
|
-
throw new Error(`Invalid n value: ${n}`);
|
|
2326
|
-
}
|
|
2327
|
-
return String.fromCharCode(code);
|
|
2328
|
-
}
|
|
2329
|
-
function makePosition(x, y) {
|
|
2330
|
-
if (x !== void 0 && y !== void 0) {
|
|
2331
|
-
return between(x, y);
|
|
2332
|
-
} else if (x !== void 0) {
|
|
2333
|
-
return after(x);
|
|
2334
|
-
} else if (y !== void 0) {
|
|
2335
|
-
return before(y);
|
|
2336
|
-
} else {
|
|
2337
|
-
return ONE;
|
|
2338
|
-
}
|
|
2339
|
-
}
|
|
2340
|
-
function before(pos) {
|
|
2341
|
-
const lastIndex = pos.length - 1;
|
|
2342
|
-
for (let i = 0; i <= lastIndex; i++) {
|
|
2343
|
-
const code = pos.charCodeAt(i);
|
|
2344
|
-
if (code <= MIN_CODE) {
|
|
2345
|
-
continue;
|
|
2436
|
+
case "NoParent": {
|
|
2437
|
+
this._parent = NoParent;
|
|
2438
|
+
break;
|
|
2439
|
+
}
|
|
2440
|
+
case "Orphaned": {
|
|
2441
|
+
break;
|
|
2442
|
+
}
|
|
2443
|
+
default:
|
|
2444
|
+
assertNever(this.parent, "Unknown state");
|
|
2346
2445
|
}
|
|
2347
|
-
|
|
2348
|
-
|
|
2349
|
-
|
|
2350
|
-
|
|
2351
|
-
|
|
2446
|
+
this.__pool = void 0;
|
|
2447
|
+
}
|
|
2448
|
+
/**
|
|
2449
|
+
* @internal
|
|
2450
|
+
*
|
|
2451
|
+
* Clear the Immutable cache, so that the next call to `.toImmutable()` will
|
|
2452
|
+
* recompute the equivalent Immutable value again. Call this after every
|
|
2453
|
+
* mutation to the Live node.
|
|
2454
|
+
*/
|
|
2455
|
+
invalidate() {
|
|
2456
|
+
if (this._cachedImmutable !== void 0 || this._cachedTreeNode !== void 0) {
|
|
2457
|
+
this._cachedImmutable = void 0;
|
|
2458
|
+
this._cachedTreeNode = void 0;
|
|
2459
|
+
if (this.parent.type === "HasParent") {
|
|
2460
|
+
this.parent.node.invalidate();
|
|
2352
2461
|
}
|
|
2353
|
-
} else {
|
|
2354
|
-
return pos.substring(0, i + 1);
|
|
2355
2462
|
}
|
|
2356
2463
|
}
|
|
2357
|
-
|
|
2358
|
-
|
|
2359
|
-
|
|
2360
|
-
|
|
2361
|
-
|
|
2362
|
-
|
|
2363
|
-
|
|
2464
|
+
/**
|
|
2465
|
+
* @internal
|
|
2466
|
+
*
|
|
2467
|
+
* Return an snapshot of this Live tree for use in DevTools.
|
|
2468
|
+
*/
|
|
2469
|
+
toTreeNode(key) {
|
|
2470
|
+
if (this._cachedTreeNode === void 0 || this._cachedTreeNodeKey !== key) {
|
|
2471
|
+
this._cachedTreeNodeKey = key;
|
|
2472
|
+
this._cachedTreeNode = this._toTreeNode(key);
|
|
2364
2473
|
}
|
|
2365
|
-
return
|
|
2474
|
+
return this._cachedTreeNode;
|
|
2366
2475
|
}
|
|
2367
|
-
|
|
2368
|
-
|
|
2369
|
-
|
|
2370
|
-
|
|
2371
|
-
|
|
2372
|
-
|
|
2373
|
-
|
|
2374
|
-
|
|
2375
|
-
throw new Error("Cannot compute value between two equal positions");
|
|
2376
|
-
}
|
|
2377
|
-
}
|
|
2378
|
-
function _between(lo, hi) {
|
|
2379
|
-
let index = 0;
|
|
2380
|
-
const loLen = lo.length;
|
|
2381
|
-
const hiLen = hi.length;
|
|
2382
|
-
while (true) {
|
|
2383
|
-
const loCode = index < loLen ? lo.charCodeAt(index) : MIN_CODE;
|
|
2384
|
-
const hiCode = index < hiLen ? hi.charCodeAt(index) : MAX_CODE;
|
|
2385
|
-
if (loCode === hiCode) {
|
|
2386
|
-
index++;
|
|
2387
|
-
continue;
|
|
2388
|
-
}
|
|
2389
|
-
if (hiCode - loCode === 1) {
|
|
2390
|
-
const size = index + 1;
|
|
2391
|
-
let prefix = lo.substring(0, size);
|
|
2392
|
-
if (prefix.length < size) {
|
|
2393
|
-
prefix += ZERO.repeat(size - prefix.length);
|
|
2394
|
-
}
|
|
2395
|
-
const suffix = lo.substring(size);
|
|
2396
|
-
const nines = "";
|
|
2397
|
-
return prefix + _between(suffix, nines);
|
|
2398
|
-
} else {
|
|
2399
|
-
return takeN(lo, index) + String.fromCharCode(hiCode + loCode >> 1);
|
|
2400
|
-
}
|
|
2401
|
-
}
|
|
2402
|
-
}
|
|
2403
|
-
function takeN(pos, n) {
|
|
2404
|
-
return n < pos.length ? pos.substring(0, n) : pos + ZERO.repeat(n - pos.length);
|
|
2405
|
-
}
|
|
2406
|
-
var MIN_NON_ZERO_CODE = MIN_CODE + 1;
|
|
2407
|
-
function isPos(str) {
|
|
2408
|
-
if (str === "") {
|
|
2409
|
-
return false;
|
|
2410
|
-
}
|
|
2411
|
-
const lastIdx = str.length - 1;
|
|
2412
|
-
const last = str.charCodeAt(lastIdx);
|
|
2413
|
-
if (last < MIN_NON_ZERO_CODE || last > MAX_CODE) {
|
|
2414
|
-
return false;
|
|
2415
|
-
}
|
|
2416
|
-
for (let i = 0; i < lastIdx; i++) {
|
|
2417
|
-
const code = str.charCodeAt(i);
|
|
2418
|
-
if (code < MIN_CODE || code > MAX_CODE) {
|
|
2419
|
-
return false;
|
|
2420
|
-
}
|
|
2421
|
-
}
|
|
2422
|
-
return true;
|
|
2423
|
-
}
|
|
2424
|
-
function convertToPos(str) {
|
|
2425
|
-
const codes = [];
|
|
2426
|
-
for (let i = 0; i < str.length; i++) {
|
|
2427
|
-
const code = str.charCodeAt(i);
|
|
2428
|
-
codes.push(code < MIN_CODE ? MIN_CODE : code > MAX_CODE ? MAX_CODE : code);
|
|
2429
|
-
}
|
|
2430
|
-
while (codes.length > 0 && codes[codes.length - 1] === MIN_CODE) {
|
|
2431
|
-
codes.length--;
|
|
2432
|
-
}
|
|
2433
|
-
return codes.length > 0 ? String.fromCharCode(...codes) : (
|
|
2434
|
-
// Edge case: the str was a 0-only string, which is invalid. Default back to .1
|
|
2435
|
-
ONE
|
|
2436
|
-
);
|
|
2437
|
-
}
|
|
2438
|
-
function asPos(str) {
|
|
2439
|
-
return isPos(str) ? str : convertToPos(str);
|
|
2440
|
-
}
|
|
2441
|
-
|
|
2442
|
-
// src/protocol/Op.ts
|
|
2443
|
-
var OpCode = /* @__PURE__ */ ((OpCode2) => {
|
|
2444
|
-
OpCode2[OpCode2["INIT"] = 0] = "INIT";
|
|
2445
|
-
OpCode2[OpCode2["SET_PARENT_KEY"] = 1] = "SET_PARENT_KEY";
|
|
2446
|
-
OpCode2[OpCode2["CREATE_LIST"] = 2] = "CREATE_LIST";
|
|
2447
|
-
OpCode2[OpCode2["UPDATE_OBJECT"] = 3] = "UPDATE_OBJECT";
|
|
2448
|
-
OpCode2[OpCode2["CREATE_OBJECT"] = 4] = "CREATE_OBJECT";
|
|
2449
|
-
OpCode2[OpCode2["DELETE_CRDT"] = 5] = "DELETE_CRDT";
|
|
2450
|
-
OpCode2[OpCode2["DELETE_OBJECT_KEY"] = 6] = "DELETE_OBJECT_KEY";
|
|
2451
|
-
OpCode2[OpCode2["CREATE_MAP"] = 7] = "CREATE_MAP";
|
|
2452
|
-
OpCode2[OpCode2["CREATE_REGISTER"] = 8] = "CREATE_REGISTER";
|
|
2453
|
-
return OpCode2;
|
|
2454
|
-
})(OpCode || {});
|
|
2455
|
-
function isAckOp(op) {
|
|
2456
|
-
return op.type === 5 /* DELETE_CRDT */ && op.id === "ACK";
|
|
2457
|
-
}
|
|
2458
|
-
|
|
2459
|
-
// src/crdts/AbstractCrdt.ts
|
|
2460
|
-
function crdtAsLiveNode(value) {
|
|
2461
|
-
return value;
|
|
2462
|
-
}
|
|
2463
|
-
function HasParent(node, key, pos = asPos(key)) {
|
|
2464
|
-
return Object.freeze({ type: "HasParent", node, key, pos });
|
|
2465
|
-
}
|
|
2466
|
-
var NoParent = Object.freeze({ type: "NoParent" });
|
|
2467
|
-
function Orphaned(oldKey, oldPos = asPos(oldKey)) {
|
|
2468
|
-
return Object.freeze({ type: "Orphaned", oldKey, oldPos });
|
|
2469
|
-
}
|
|
2470
|
-
var AbstractCrdt = class {
|
|
2471
|
-
constructor() {
|
|
2472
|
-
/** @internal */
|
|
2473
|
-
this._parent = NoParent;
|
|
2474
|
-
}
|
|
2475
|
-
/** @internal */
|
|
2476
|
-
_getParentKeyOrThrow() {
|
|
2477
|
-
switch (this.parent.type) {
|
|
2478
|
-
case "HasParent":
|
|
2479
|
-
return this.parent.key;
|
|
2480
|
-
case "NoParent":
|
|
2481
|
-
throw new Error("Parent key is missing");
|
|
2482
|
-
case "Orphaned":
|
|
2483
|
-
return this.parent.oldKey;
|
|
2484
|
-
default:
|
|
2485
|
-
return assertNever(this.parent, "Unknown state");
|
|
2486
|
-
}
|
|
2487
|
-
}
|
|
2488
|
-
/** @internal */
|
|
2489
|
-
get _parentPos() {
|
|
2490
|
-
switch (this.parent.type) {
|
|
2491
|
-
case "HasParent":
|
|
2492
|
-
return this.parent.pos;
|
|
2493
|
-
case "NoParent":
|
|
2494
|
-
throw new Error("Parent key is missing");
|
|
2495
|
-
case "Orphaned":
|
|
2496
|
-
return this.parent.oldPos;
|
|
2497
|
-
default:
|
|
2498
|
-
return assertNever(this.parent, "Unknown state");
|
|
2499
|
-
}
|
|
2500
|
-
}
|
|
2501
|
-
/** @internal */
|
|
2502
|
-
get _pool() {
|
|
2503
|
-
return this.__pool;
|
|
2504
|
-
}
|
|
2505
|
-
get roomId() {
|
|
2506
|
-
return this.__pool ? this.__pool.roomId : null;
|
|
2507
|
-
}
|
|
2508
|
-
/** @internal */
|
|
2509
|
-
get _id() {
|
|
2510
|
-
return this.__id;
|
|
2511
|
-
}
|
|
2512
|
-
/** @internal */
|
|
2513
|
-
get parent() {
|
|
2514
|
-
return this._parent;
|
|
2515
|
-
}
|
|
2516
|
-
/** @internal */
|
|
2517
|
-
get _parentKey() {
|
|
2518
|
-
switch (this.parent.type) {
|
|
2519
|
-
case "HasParent":
|
|
2520
|
-
return this.parent.key;
|
|
2521
|
-
case "NoParent":
|
|
2522
|
-
return null;
|
|
2523
|
-
case "Orphaned":
|
|
2524
|
-
return this.parent.oldKey;
|
|
2525
|
-
default:
|
|
2526
|
-
return assertNever(this.parent, "Unknown state");
|
|
2527
|
-
}
|
|
2528
|
-
}
|
|
2529
|
-
/** @internal */
|
|
2530
|
-
_apply(op, _isLocal) {
|
|
2531
|
-
switch (op.type) {
|
|
2532
|
-
case 5 /* DELETE_CRDT */: {
|
|
2533
|
-
if (this.parent.type === "HasParent") {
|
|
2534
|
-
return this.parent.node._detachChild(crdtAsLiveNode(this));
|
|
2535
|
-
}
|
|
2536
|
-
return { modified: false };
|
|
2537
|
-
}
|
|
2538
|
-
}
|
|
2539
|
-
return { modified: false };
|
|
2540
|
-
}
|
|
2541
|
-
/** @internal */
|
|
2542
|
-
_setParentLink(newParentNode, newParentKey) {
|
|
2543
|
-
switch (this.parent.type) {
|
|
2544
|
-
case "HasParent":
|
|
2545
|
-
if (this.parent.node !== newParentNode) {
|
|
2546
|
-
throw new Error("Cannot set parent: node already has a parent");
|
|
2547
|
-
} else {
|
|
2548
|
-
this._parent = HasParent(newParentNode, newParentKey);
|
|
2549
|
-
return;
|
|
2550
|
-
}
|
|
2551
|
-
case "Orphaned":
|
|
2552
|
-
case "NoParent": {
|
|
2553
|
-
this._parent = HasParent(newParentNode, newParentKey);
|
|
2554
|
-
return;
|
|
2555
|
-
}
|
|
2556
|
-
default:
|
|
2557
|
-
return assertNever(this.parent, "Unknown state");
|
|
2558
|
-
}
|
|
2559
|
-
}
|
|
2560
|
-
/** @internal */
|
|
2561
|
-
_attach(id, pool) {
|
|
2562
|
-
if (this.__id || this.__pool) {
|
|
2563
|
-
throw new Error("Cannot attach node: already attached");
|
|
2564
|
-
}
|
|
2565
|
-
pool.addNode(id, crdtAsLiveNode(this));
|
|
2566
|
-
this.__id = id;
|
|
2567
|
-
this.__pool = pool;
|
|
2568
|
-
}
|
|
2569
|
-
/** @internal */
|
|
2570
|
-
_detach() {
|
|
2571
|
-
if (this.__pool && this.__id) {
|
|
2572
|
-
this.__pool.deleteNode(this.__id);
|
|
2573
|
-
}
|
|
2574
|
-
switch (this.parent.type) {
|
|
2575
|
-
case "HasParent": {
|
|
2576
|
-
this._parent = Orphaned(this.parent.key, this.parent.pos);
|
|
2577
|
-
break;
|
|
2578
|
-
}
|
|
2579
|
-
case "NoParent": {
|
|
2580
|
-
this._parent = NoParent;
|
|
2581
|
-
break;
|
|
2582
|
-
}
|
|
2583
|
-
case "Orphaned": {
|
|
2584
|
-
break;
|
|
2585
|
-
}
|
|
2586
|
-
default:
|
|
2587
|
-
assertNever(this.parent, "Unknown state");
|
|
2588
|
-
}
|
|
2589
|
-
this.__pool = void 0;
|
|
2590
|
-
}
|
|
2591
|
-
/**
|
|
2592
|
-
* @internal
|
|
2593
|
-
*
|
|
2594
|
-
* Clear the Immutable cache, so that the next call to `.toImmutable()` will
|
|
2595
|
-
* recompute the equivalent Immutable value again. Call this after every
|
|
2596
|
-
* mutation to the Live node.
|
|
2597
|
-
*/
|
|
2598
|
-
invalidate() {
|
|
2599
|
-
if (this._cachedImmutable !== void 0 || this._cachedTreeNode !== void 0) {
|
|
2600
|
-
this._cachedImmutable = void 0;
|
|
2601
|
-
this._cachedTreeNode = void 0;
|
|
2602
|
-
if (this.parent.type === "HasParent") {
|
|
2603
|
-
this.parent.node.invalidate();
|
|
2604
|
-
}
|
|
2605
|
-
}
|
|
2606
|
-
}
|
|
2607
|
-
/**
|
|
2608
|
-
* @internal
|
|
2609
|
-
*
|
|
2610
|
-
* Return an snapshot of this Live tree for use in DevTools.
|
|
2611
|
-
*/
|
|
2612
|
-
toTreeNode(key) {
|
|
2613
|
-
if (this._cachedTreeNode === void 0 || this._cachedTreeNodeKey !== key) {
|
|
2614
|
-
this._cachedTreeNodeKey = key;
|
|
2615
|
-
this._cachedTreeNode = this._toTreeNode(key);
|
|
2616
|
-
}
|
|
2617
|
-
return this._cachedTreeNode;
|
|
2618
|
-
}
|
|
2619
|
-
/**
|
|
2620
|
-
* Return an immutable snapshot of this Live node and its children.
|
|
2621
|
-
*/
|
|
2622
|
-
toImmutable() {
|
|
2623
|
-
if (this._cachedImmutable === void 0) {
|
|
2624
|
-
this._cachedImmutable = this._toImmutable();
|
|
2625
|
-
}
|
|
2626
|
-
return this._cachedImmutable;
|
|
2476
|
+
/**
|
|
2477
|
+
* Return an immutable snapshot of this Live node and its children.
|
|
2478
|
+
*/
|
|
2479
|
+
toImmutable() {
|
|
2480
|
+
if (this._cachedImmutable === void 0) {
|
|
2481
|
+
this._cachedImmutable = this._toImmutable();
|
|
2482
|
+
}
|
|
2483
|
+
return this._cachedImmutable;
|
|
2627
2484
|
}
|
|
2628
2485
|
};
|
|
2629
2486
|
|
|
@@ -4097,19 +3954,6 @@ var LiveMap = class _LiveMap extends AbstractCrdt {
|
|
|
4097
3954
|
|
|
4098
3955
|
// src/crdts/LiveObject.ts
|
|
4099
3956
|
var LiveObject = class _LiveObject extends AbstractCrdt {
|
|
4100
|
-
constructor(obj = {}) {
|
|
4101
|
-
super();
|
|
4102
|
-
this._propToLastUpdate = /* @__PURE__ */ new Map();
|
|
4103
|
-
for (const key in obj) {
|
|
4104
|
-
const value = obj[key];
|
|
4105
|
-
if (value === void 0) {
|
|
4106
|
-
continue;
|
|
4107
|
-
} else if (isLiveNode(value)) {
|
|
4108
|
-
value._setParentLink(this, key);
|
|
4109
|
-
}
|
|
4110
|
-
}
|
|
4111
|
-
this._map = new Map(Object.entries(obj));
|
|
4112
|
-
}
|
|
4113
3957
|
/** @internal */
|
|
4114
3958
|
static _buildRootAndParentToChildren(items) {
|
|
4115
3959
|
const parentToChildren = /* @__PURE__ */ new Map();
|
|
@@ -4141,10 +3985,22 @@ var LiveObject = class _LiveObject extends AbstractCrdt {
|
|
|
4141
3985
|
pool
|
|
4142
3986
|
);
|
|
4143
3987
|
}
|
|
4144
|
-
|
|
4145
|
-
|
|
4146
|
-
|
|
4147
|
-
|
|
3988
|
+
constructor(obj = {}) {
|
|
3989
|
+
super();
|
|
3990
|
+
this._propToLastUpdate = /* @__PURE__ */ new Map();
|
|
3991
|
+
const o = compactObject(obj);
|
|
3992
|
+
for (const key of Object.keys(o)) {
|
|
3993
|
+
const value = o[key];
|
|
3994
|
+
if (isLiveNode(value)) {
|
|
3995
|
+
value._setParentLink(this, key);
|
|
3996
|
+
}
|
|
3997
|
+
}
|
|
3998
|
+
this._map = new Map(Object.entries(o));
|
|
3999
|
+
}
|
|
4000
|
+
/** @internal */
|
|
4001
|
+
_toOps(parentId, parentKey, pool) {
|
|
4002
|
+
if (this._id === void 0) {
|
|
4003
|
+
throw new Error("Cannot serialize item is not attached");
|
|
4148
4004
|
}
|
|
4149
4005
|
const opId = pool?.generateOpId();
|
|
4150
4006
|
const ops = [];
|
|
@@ -4886,6 +4742,115 @@ function isJsonObject(data) {
|
|
|
4886
4742
|
return !isJsonScalar(data) && !isJsonArray(data);
|
|
4887
4743
|
}
|
|
4888
4744
|
|
|
4745
|
+
// src/lib/objectToQuery.ts
|
|
4746
|
+
var identifierRegex = /^[a-zA-Z_][a-zA-Z0-9_]*$/;
|
|
4747
|
+
function objectToQuery(obj) {
|
|
4748
|
+
let filterList = [];
|
|
4749
|
+
const entries2 = Object.entries(obj);
|
|
4750
|
+
const keyValuePairs = [];
|
|
4751
|
+
const keyValuePairsWithOperator = [];
|
|
4752
|
+
const indexedKeys = [];
|
|
4753
|
+
entries2.forEach(([key, value]) => {
|
|
4754
|
+
if (!identifierRegex.test(key)) {
|
|
4755
|
+
throw new Error("Key must only contain letters, numbers, _");
|
|
4756
|
+
}
|
|
4757
|
+
if (isSimpleValue(value)) {
|
|
4758
|
+
keyValuePairs.push([key, value]);
|
|
4759
|
+
} else if (isValueWithOperator(value)) {
|
|
4760
|
+
keyValuePairsWithOperator.push([key, value]);
|
|
4761
|
+
} else if (typeof value === "object" && !("startsWith" in value)) {
|
|
4762
|
+
indexedKeys.push([key, value]);
|
|
4763
|
+
}
|
|
4764
|
+
});
|
|
4765
|
+
filterList = [
|
|
4766
|
+
...getFiltersFromKeyValuePairs(keyValuePairs),
|
|
4767
|
+
...getFiltersFromKeyValuePairsWithOperator(keyValuePairsWithOperator)
|
|
4768
|
+
];
|
|
4769
|
+
indexedKeys.forEach(([key, value]) => {
|
|
4770
|
+
const nestedEntries = Object.entries(value);
|
|
4771
|
+
const nKeyValuePairs = [];
|
|
4772
|
+
const nKeyValuePairsWithOperator = [];
|
|
4773
|
+
nestedEntries.forEach(([nestedKey, nestedValue]) => {
|
|
4774
|
+
if (isStringEmpty(nestedKey)) {
|
|
4775
|
+
throw new Error("Key cannot be empty");
|
|
4776
|
+
}
|
|
4777
|
+
if (isSimpleValue(nestedValue)) {
|
|
4778
|
+
nKeyValuePairs.push([formatFilterKey(key, nestedKey), nestedValue]);
|
|
4779
|
+
} else if (isValueWithOperator(nestedValue)) {
|
|
4780
|
+
nKeyValuePairsWithOperator.push([
|
|
4781
|
+
formatFilterKey(key, nestedKey),
|
|
4782
|
+
nestedValue
|
|
4783
|
+
]);
|
|
4784
|
+
}
|
|
4785
|
+
});
|
|
4786
|
+
filterList = [
|
|
4787
|
+
...filterList,
|
|
4788
|
+
...getFiltersFromKeyValuePairs(nKeyValuePairs),
|
|
4789
|
+
...getFiltersFromKeyValuePairsWithOperator(nKeyValuePairsWithOperator)
|
|
4790
|
+
];
|
|
4791
|
+
});
|
|
4792
|
+
return filterList.map(
|
|
4793
|
+
({ key, operator, value }) => formatFilter(key, operator, formatFilterValue(value))
|
|
4794
|
+
).join(" AND ");
|
|
4795
|
+
}
|
|
4796
|
+
var getFiltersFromKeyValuePairs = (keyValuePairs) => {
|
|
4797
|
+
const filters = [];
|
|
4798
|
+
keyValuePairs.forEach(([key, value]) => {
|
|
4799
|
+
filters.push({
|
|
4800
|
+
key,
|
|
4801
|
+
operator: ":",
|
|
4802
|
+
value
|
|
4803
|
+
});
|
|
4804
|
+
});
|
|
4805
|
+
return filters;
|
|
4806
|
+
};
|
|
4807
|
+
var getFiltersFromKeyValuePairsWithOperator = (keyValuePairsWithOperator) => {
|
|
4808
|
+
const filters = [];
|
|
4809
|
+
keyValuePairsWithOperator.forEach(([key, value]) => {
|
|
4810
|
+
if ("startsWith" in value && typeof value.startsWith === "string") {
|
|
4811
|
+
filters.push({
|
|
4812
|
+
key,
|
|
4813
|
+
operator: "^",
|
|
4814
|
+
value: value.startsWith
|
|
4815
|
+
});
|
|
4816
|
+
}
|
|
4817
|
+
});
|
|
4818
|
+
return filters;
|
|
4819
|
+
};
|
|
4820
|
+
var isSimpleValue = (value) => {
|
|
4821
|
+
if (typeof value === "string" || typeof value === "number" || typeof value === "boolean") {
|
|
4822
|
+
return true;
|
|
4823
|
+
}
|
|
4824
|
+
return false;
|
|
4825
|
+
};
|
|
4826
|
+
var isValueWithOperator = (value) => {
|
|
4827
|
+
if (typeof value === "object" && value !== null && "startsWith" in value) {
|
|
4828
|
+
return true;
|
|
4829
|
+
}
|
|
4830
|
+
return false;
|
|
4831
|
+
};
|
|
4832
|
+
var formatFilter = (key, operator, value) => {
|
|
4833
|
+
return `${key}${operator}${value}`;
|
|
4834
|
+
};
|
|
4835
|
+
var formatFilterKey = (key, nestedKey) => {
|
|
4836
|
+
if (nestedKey) {
|
|
4837
|
+
return `${key}[${JSON.stringify(nestedKey)}]`;
|
|
4838
|
+
}
|
|
4839
|
+
return key;
|
|
4840
|
+
};
|
|
4841
|
+
var formatFilterValue = (value) => {
|
|
4842
|
+
if (typeof value === "string") {
|
|
4843
|
+
if (isStringEmpty(value)) {
|
|
4844
|
+
throw new Error("Value cannot be empty");
|
|
4845
|
+
}
|
|
4846
|
+
return JSON.stringify(value);
|
|
4847
|
+
}
|
|
4848
|
+
return value.toString();
|
|
4849
|
+
};
|
|
4850
|
+
var isStringEmpty = (value) => {
|
|
4851
|
+
return !value || value.toString().trim() === "";
|
|
4852
|
+
};
|
|
4853
|
+
|
|
4889
4854
|
// src/protocol/ClientMsg.ts
|
|
4890
4855
|
var ClientMsgCode = /* @__PURE__ */ ((ClientMsgCode2) => {
|
|
4891
4856
|
ClientMsgCode2[ClientMsgCode2["UPDATE_PRESENCE"] = 100] = "UPDATE_PRESENCE";
|
|
@@ -5129,7 +5094,13 @@ function userToTreeNode(key, user) {
|
|
|
5129
5094
|
type: "User",
|
|
5130
5095
|
id: `${user.connectionId}`,
|
|
5131
5096
|
key,
|
|
5132
|
-
payload:
|
|
5097
|
+
payload: {
|
|
5098
|
+
connectionId: user.connectionId,
|
|
5099
|
+
id: user.id,
|
|
5100
|
+
info: user.info,
|
|
5101
|
+
presence: user.presence,
|
|
5102
|
+
isReadOnly: !user.canWrite
|
|
5103
|
+
}
|
|
5133
5104
|
};
|
|
5134
5105
|
}
|
|
5135
5106
|
function installBackgroundTabSpy() {
|
|
@@ -5148,6 +5119,246 @@ function installBackgroundTabSpy() {
|
|
|
5148
5119
|
};
|
|
5149
5120
|
return [inBackgroundSince, unsub];
|
|
5150
5121
|
}
|
|
5122
|
+
var CommentsApiError = class extends Error {
|
|
5123
|
+
constructor(message, status, details) {
|
|
5124
|
+
super(message);
|
|
5125
|
+
this.message = message;
|
|
5126
|
+
this.status = status;
|
|
5127
|
+
this.details = details;
|
|
5128
|
+
}
|
|
5129
|
+
};
|
|
5130
|
+
function createCommentsApi(roomId, getAuthValue, fetchClientApi) {
|
|
5131
|
+
async function fetchCommentsApi(endpoint, params, options) {
|
|
5132
|
+
const authValue = await getAuthValue();
|
|
5133
|
+
return fetchClientApi(roomId, endpoint, authValue, options, params);
|
|
5134
|
+
}
|
|
5135
|
+
async function fetchJson(endpoint, options, params) {
|
|
5136
|
+
const response = await fetchCommentsApi(endpoint, params, options);
|
|
5137
|
+
if (!response.ok) {
|
|
5138
|
+
if (response.status >= 400 && response.status < 600) {
|
|
5139
|
+
let error3;
|
|
5140
|
+
try {
|
|
5141
|
+
const errorBody = await response.json();
|
|
5142
|
+
error3 = new CommentsApiError(
|
|
5143
|
+
errorBody.message,
|
|
5144
|
+
response.status,
|
|
5145
|
+
errorBody
|
|
5146
|
+
);
|
|
5147
|
+
} catch {
|
|
5148
|
+
error3 = new CommentsApiError(response.statusText, response.status);
|
|
5149
|
+
}
|
|
5150
|
+
throw error3;
|
|
5151
|
+
}
|
|
5152
|
+
}
|
|
5153
|
+
let body;
|
|
5154
|
+
try {
|
|
5155
|
+
body = await response.json();
|
|
5156
|
+
} catch {
|
|
5157
|
+
body = {};
|
|
5158
|
+
}
|
|
5159
|
+
return body;
|
|
5160
|
+
}
|
|
5161
|
+
async function getThreads(options) {
|
|
5162
|
+
let query;
|
|
5163
|
+
if (options?.query) {
|
|
5164
|
+
query = objectToQuery(options.query);
|
|
5165
|
+
}
|
|
5166
|
+
const response = await fetchCommentsApi(
|
|
5167
|
+
"/threads",
|
|
5168
|
+
{
|
|
5169
|
+
since: options?.since?.toISOString(),
|
|
5170
|
+
query
|
|
5171
|
+
},
|
|
5172
|
+
{
|
|
5173
|
+
headers: {
|
|
5174
|
+
"Content-Type": "application/json"
|
|
5175
|
+
}
|
|
5176
|
+
}
|
|
5177
|
+
);
|
|
5178
|
+
if (response.ok) {
|
|
5179
|
+
const json = await response.json();
|
|
5180
|
+
return {
|
|
5181
|
+
threads: json.data.map((thread) => convertToThreadData(thread)),
|
|
5182
|
+
inboxNotifications: json.inboxNotifications.map(
|
|
5183
|
+
(notification) => convertToInboxNotificationData(notification)
|
|
5184
|
+
),
|
|
5185
|
+
deletedThreads: json.deletedThreads.map(
|
|
5186
|
+
(info) => convertToThreadDeleteInfo(info)
|
|
5187
|
+
),
|
|
5188
|
+
deletedInboxNotifications: json.deletedInboxNotifications.map(
|
|
5189
|
+
(info) => convertToInboxNotificationDeleteInfo(info)
|
|
5190
|
+
),
|
|
5191
|
+
meta: {
|
|
5192
|
+
requestedAt: new Date(json.meta.requestedAt)
|
|
5193
|
+
}
|
|
5194
|
+
};
|
|
5195
|
+
} else if (response.status === 404) {
|
|
5196
|
+
return {
|
|
5197
|
+
threads: [],
|
|
5198
|
+
inboxNotifications: [],
|
|
5199
|
+
deletedThreads: [],
|
|
5200
|
+
deletedInboxNotifications: [],
|
|
5201
|
+
meta: {
|
|
5202
|
+
requestedAt: /* @__PURE__ */ new Date()
|
|
5203
|
+
}
|
|
5204
|
+
};
|
|
5205
|
+
} else {
|
|
5206
|
+
throw new Error("There was an error while getting threads.");
|
|
5207
|
+
}
|
|
5208
|
+
}
|
|
5209
|
+
async function getThread({ threadId }) {
|
|
5210
|
+
const response = await fetchCommentsApi(
|
|
5211
|
+
`/thread-with-notification/${threadId}`
|
|
5212
|
+
);
|
|
5213
|
+
if (response.ok) {
|
|
5214
|
+
const json = await response.json();
|
|
5215
|
+
return {
|
|
5216
|
+
thread: convertToThreadData(json.thread),
|
|
5217
|
+
inboxNotification: json.inboxNotification ? convertToInboxNotificationData(json.inboxNotification) : void 0
|
|
5218
|
+
};
|
|
5219
|
+
} else if (response.status === 404) {
|
|
5220
|
+
return;
|
|
5221
|
+
} else {
|
|
5222
|
+
throw new Error(`There was an error while getting thread ${threadId}.`);
|
|
5223
|
+
}
|
|
5224
|
+
}
|
|
5225
|
+
async function createThread({
|
|
5226
|
+
metadata,
|
|
5227
|
+
body,
|
|
5228
|
+
commentId,
|
|
5229
|
+
threadId
|
|
5230
|
+
}) {
|
|
5231
|
+
const thread = await fetchJson("/threads", {
|
|
5232
|
+
method: "POST",
|
|
5233
|
+
headers: {
|
|
5234
|
+
"Content-Type": "application/json"
|
|
5235
|
+
},
|
|
5236
|
+
body: JSON.stringify({
|
|
5237
|
+
id: threadId,
|
|
5238
|
+
comment: {
|
|
5239
|
+
id: commentId,
|
|
5240
|
+
body
|
|
5241
|
+
},
|
|
5242
|
+
metadata
|
|
5243
|
+
})
|
|
5244
|
+
});
|
|
5245
|
+
return convertToThreadData(thread);
|
|
5246
|
+
}
|
|
5247
|
+
async function editThreadMetadata({
|
|
5248
|
+
metadata,
|
|
5249
|
+
threadId
|
|
5250
|
+
}) {
|
|
5251
|
+
return await fetchJson(
|
|
5252
|
+
`/threads/${encodeURIComponent(threadId)}/metadata`,
|
|
5253
|
+
{
|
|
5254
|
+
method: "POST",
|
|
5255
|
+
headers: {
|
|
5256
|
+
"Content-Type": "application/json"
|
|
5257
|
+
},
|
|
5258
|
+
body: JSON.stringify(metadata)
|
|
5259
|
+
}
|
|
5260
|
+
);
|
|
5261
|
+
}
|
|
5262
|
+
async function createComment({
|
|
5263
|
+
threadId,
|
|
5264
|
+
commentId,
|
|
5265
|
+
body
|
|
5266
|
+
}) {
|
|
5267
|
+
const comment = await fetchJson(
|
|
5268
|
+
`/threads/${encodeURIComponent(threadId)}/comments`,
|
|
5269
|
+
{
|
|
5270
|
+
method: "POST",
|
|
5271
|
+
headers: {
|
|
5272
|
+
"Content-Type": "application/json"
|
|
5273
|
+
},
|
|
5274
|
+
body: JSON.stringify({
|
|
5275
|
+
id: commentId,
|
|
5276
|
+
body
|
|
5277
|
+
})
|
|
5278
|
+
}
|
|
5279
|
+
);
|
|
5280
|
+
return convertToCommentData(comment);
|
|
5281
|
+
}
|
|
5282
|
+
async function editComment({
|
|
5283
|
+
threadId,
|
|
5284
|
+
commentId,
|
|
5285
|
+
body
|
|
5286
|
+
}) {
|
|
5287
|
+
const comment = await fetchJson(
|
|
5288
|
+
`/threads/${encodeURIComponent(threadId)}/comments/${encodeURIComponent(
|
|
5289
|
+
commentId
|
|
5290
|
+
)}`,
|
|
5291
|
+
{
|
|
5292
|
+
method: "POST",
|
|
5293
|
+
headers: {
|
|
5294
|
+
"Content-Type": "application/json"
|
|
5295
|
+
},
|
|
5296
|
+
body: JSON.stringify({
|
|
5297
|
+
body
|
|
5298
|
+
})
|
|
5299
|
+
}
|
|
5300
|
+
);
|
|
5301
|
+
return convertToCommentData(comment);
|
|
5302
|
+
}
|
|
5303
|
+
async function deleteComment2({
|
|
5304
|
+
threadId,
|
|
5305
|
+
commentId
|
|
5306
|
+
}) {
|
|
5307
|
+
await fetchJson(
|
|
5308
|
+
`/threads/${encodeURIComponent(threadId)}/comments/${encodeURIComponent(
|
|
5309
|
+
commentId
|
|
5310
|
+
)}`,
|
|
5311
|
+
{
|
|
5312
|
+
method: "DELETE"
|
|
5313
|
+
}
|
|
5314
|
+
);
|
|
5315
|
+
}
|
|
5316
|
+
async function addReaction2({
|
|
5317
|
+
threadId,
|
|
5318
|
+
commentId,
|
|
5319
|
+
emoji
|
|
5320
|
+
}) {
|
|
5321
|
+
const reaction = await fetchJson(
|
|
5322
|
+
`/threads/${encodeURIComponent(threadId)}/comments/${encodeURIComponent(
|
|
5323
|
+
commentId
|
|
5324
|
+
)}/reactions`,
|
|
5325
|
+
{
|
|
5326
|
+
method: "POST",
|
|
5327
|
+
headers: {
|
|
5328
|
+
"Content-Type": "application/json"
|
|
5329
|
+
},
|
|
5330
|
+
body: JSON.stringify({ emoji })
|
|
5331
|
+
}
|
|
5332
|
+
);
|
|
5333
|
+
return convertToCommentUserReaction(reaction);
|
|
5334
|
+
}
|
|
5335
|
+
async function removeReaction2({
|
|
5336
|
+
threadId,
|
|
5337
|
+
commentId,
|
|
5338
|
+
emoji
|
|
5339
|
+
}) {
|
|
5340
|
+
await fetchJson(
|
|
5341
|
+
`/threads/${encodeURIComponent(threadId)}/comments/${encodeURIComponent(
|
|
5342
|
+
commentId
|
|
5343
|
+
)}/reactions/${encodeURIComponent(emoji)}`,
|
|
5344
|
+
{
|
|
5345
|
+
method: "DELETE"
|
|
5346
|
+
}
|
|
5347
|
+
);
|
|
5348
|
+
}
|
|
5349
|
+
return {
|
|
5350
|
+
getThreads,
|
|
5351
|
+
getThread,
|
|
5352
|
+
createThread,
|
|
5353
|
+
editThreadMetadata,
|
|
5354
|
+
createComment,
|
|
5355
|
+
editComment,
|
|
5356
|
+
deleteComment: deleteComment2,
|
|
5357
|
+
addReaction: addReaction2,
|
|
5358
|
+
removeReaction: removeReaction2
|
|
5359
|
+
};
|
|
5360
|
+
}
|
|
5361
|
+
var MARK_INBOX_NOTIFICATIONS_AS_READ_BATCH_DELAY2 = 50;
|
|
5151
5362
|
function createRoom(options, config) {
|
|
5152
5363
|
const initialPresence = typeof options.initialPresence === "function" ? options.initialPresence(config.roomId) : options.initialPresence;
|
|
5153
5364
|
const initialStorage = typeof options.initialStorage === "function" ? options.initialStorage(config.roomId) : options.initialStorage;
|
|
@@ -5209,7 +5420,7 @@ function createRoom(options, config) {
|
|
|
5209
5420
|
function onStatusDidChange(newStatus) {
|
|
5210
5421
|
const authValue = managedSocket.authValue;
|
|
5211
5422
|
if (authValue !== null) {
|
|
5212
|
-
const tokenKey = authValue
|
|
5423
|
+
const tokenKey = getAuthBearerHeaderFromAuthValue(authValue);
|
|
5213
5424
|
if (tokenKey !== lastTokenKey) {
|
|
5214
5425
|
lastTokenKey = tokenKey;
|
|
5215
5426
|
if (authValue.type === "secret") {
|
|
@@ -5312,7 +5523,9 @@ function createRoom(options, config) {
|
|
|
5312
5523
|
}
|
|
5313
5524
|
}
|
|
5314
5525
|
if (activeBatch) {
|
|
5315
|
-
|
|
5526
|
+
for (const op of ops) {
|
|
5527
|
+
activeBatch.ops.push(op);
|
|
5528
|
+
}
|
|
5316
5529
|
for (const [key, value] of storageUpdates) {
|
|
5317
5530
|
activeBatch.updates.storageUpdates.set(
|
|
5318
5531
|
key,
|
|
@@ -5346,8 +5559,6 @@ function createRoom(options, config) {
|
|
|
5346
5559
|
}
|
|
5347
5560
|
};
|
|
5348
5561
|
const eventHub = {
|
|
5349
|
-
connection: makeEventSource(),
|
|
5350
|
-
// Old/deprecated API
|
|
5351
5562
|
status: makeEventSource(),
|
|
5352
5563
|
// New/recommended API
|
|
5353
5564
|
lostConnection: makeEventSource(),
|
|
@@ -5363,27 +5574,89 @@ function createRoom(options, config) {
|
|
|
5363
5574
|
ydoc: makeEventSource(),
|
|
5364
5575
|
comments: makeEventSource()
|
|
5365
5576
|
};
|
|
5577
|
+
async function fetchClientApi(roomId, endpoint, authValue, options2, params) {
|
|
5578
|
+
const url = urljoin(
|
|
5579
|
+
config.baseUrl,
|
|
5580
|
+
`/v2/c/rooms/${encodeURIComponent(roomId)}${endpoint}`,
|
|
5581
|
+
params
|
|
5582
|
+
);
|
|
5583
|
+
const fetcher = config.polyfills?.fetch || /* istanbul ignore next */
|
|
5584
|
+
fetch;
|
|
5585
|
+
return await fetcher(url, {
|
|
5586
|
+
...options2,
|
|
5587
|
+
headers: {
|
|
5588
|
+
...options2?.headers,
|
|
5589
|
+
Authorization: `Bearer ${getAuthBearerHeaderFromAuthValue(authValue)}`
|
|
5590
|
+
}
|
|
5591
|
+
});
|
|
5592
|
+
}
|
|
5593
|
+
async function streamFetch(authValue, roomId) {
|
|
5594
|
+
return fetchClientApi(roomId, "/storage", authValue, {
|
|
5595
|
+
method: "GET",
|
|
5596
|
+
headers: {
|
|
5597
|
+
"Content-Type": "application/json"
|
|
5598
|
+
}
|
|
5599
|
+
});
|
|
5600
|
+
}
|
|
5366
5601
|
async function httpPostToRoom(endpoint, body) {
|
|
5367
5602
|
if (!managedSocket.authValue) {
|
|
5368
5603
|
throw new Error("Not authorized");
|
|
5369
5604
|
}
|
|
5370
|
-
|
|
5371
|
-
const url = new URL(
|
|
5372
|
-
`/v2/c/rooms/${encodeURIComponent(config.roomId)}${endpoint}`,
|
|
5373
|
-
config.baseUrl
|
|
5374
|
-
).toString();
|
|
5375
|
-
const fetcher = config.polyfills?.fetch || /* istanbul ignore next */
|
|
5376
|
-
fetch;
|
|
5377
|
-
return fetcher(url, {
|
|
5605
|
+
return fetchClientApi(config.roomId, endpoint, managedSocket.authValue, {
|
|
5378
5606
|
method: "POST",
|
|
5379
5607
|
headers: {
|
|
5380
|
-
"Content-Type": "application/json"
|
|
5381
|
-
Authorization: `Bearer ${authTokenOrPublicApiKey}`
|
|
5608
|
+
"Content-Type": "application/json"
|
|
5382
5609
|
},
|
|
5383
5610
|
body: JSON.stringify(body)
|
|
5384
5611
|
});
|
|
5385
5612
|
}
|
|
5386
|
-
function
|
|
5613
|
+
async function createTextMention(userId, mentionId) {
|
|
5614
|
+
if (!managedSocket.authValue) {
|
|
5615
|
+
throw new Error("Not authorized");
|
|
5616
|
+
}
|
|
5617
|
+
return fetchClientApi(
|
|
5618
|
+
config.roomId,
|
|
5619
|
+
"/text-mentions",
|
|
5620
|
+
managedSocket.authValue,
|
|
5621
|
+
{
|
|
5622
|
+
method: "POST",
|
|
5623
|
+
headers: {
|
|
5624
|
+
"Content-Type": "application/json"
|
|
5625
|
+
},
|
|
5626
|
+
body: JSON.stringify({
|
|
5627
|
+
userId,
|
|
5628
|
+
mentionId
|
|
5629
|
+
})
|
|
5630
|
+
}
|
|
5631
|
+
);
|
|
5632
|
+
}
|
|
5633
|
+
async function deleteTextMention(mentionId) {
|
|
5634
|
+
if (!managedSocket.authValue) {
|
|
5635
|
+
throw new Error("Not authorized");
|
|
5636
|
+
}
|
|
5637
|
+
return fetchClientApi(
|
|
5638
|
+
config.roomId,
|
|
5639
|
+
`/text-mentions/${mentionId}`,
|
|
5640
|
+
managedSocket.authValue,
|
|
5641
|
+
{
|
|
5642
|
+
method: "DELETE"
|
|
5643
|
+
}
|
|
5644
|
+
);
|
|
5645
|
+
}
|
|
5646
|
+
async function reportTextEditor(type, rootKey) {
|
|
5647
|
+
const authValue = await delegates.authenticate();
|
|
5648
|
+
return fetchClientApi(config.roomId, "/text-metadata", authValue, {
|
|
5649
|
+
method: "POST",
|
|
5650
|
+
headers: {
|
|
5651
|
+
"Content-Type": "application/json"
|
|
5652
|
+
},
|
|
5653
|
+
body: JSON.stringify({
|
|
5654
|
+
type,
|
|
5655
|
+
rootKey
|
|
5656
|
+
})
|
|
5657
|
+
});
|
|
5658
|
+
}
|
|
5659
|
+
function sendMessages(messages) {
|
|
5387
5660
|
const serializedPayload = JSON.stringify(messages);
|
|
5388
5661
|
const nonce = context.dynamicSessionInfo.current?.nonce;
|
|
5389
5662
|
if (config.unstable_fallbackToHTTP && nonce) {
|
|
@@ -5419,9 +5692,7 @@ function createRoom(options, config) {
|
|
|
5419
5692
|
info: staticSession.userInfo,
|
|
5420
5693
|
presence: myPresence,
|
|
5421
5694
|
canWrite,
|
|
5422
|
-
canComment: canComment(dynamicSession.scopes)
|
|
5423
|
-
isReadOnly: !canWrite
|
|
5424
|
-
// Deprecated, kept for backward-compatibility
|
|
5695
|
+
canComment: canComment(dynamicSession.scopes)
|
|
5425
5696
|
};
|
|
5426
5697
|
}
|
|
5427
5698
|
}
|
|
@@ -5834,12 +6105,7 @@ function createRoom(options, config) {
|
|
|
5834
6105
|
break;
|
|
5835
6106
|
}
|
|
5836
6107
|
case 200 /* INITIAL_STORAGE_STATE */: {
|
|
5837
|
-
|
|
5838
|
-
createOrUpdateRootFromMessage(message, doNotBatchUpdates);
|
|
5839
|
-
applyAndSendOps(unacknowledgedOps, doNotBatchUpdates);
|
|
5840
|
-
_resolveStoragePromise?.();
|
|
5841
|
-
notifyStorageStatus();
|
|
5842
|
-
eventHub.storageDidLoad.notify();
|
|
6108
|
+
processInitialStorage(message);
|
|
5843
6109
|
break;
|
|
5844
6110
|
}
|
|
5845
6111
|
case 201 /* UPDATE_STORAGE */: {
|
|
@@ -5980,14 +6246,35 @@ ${Array.from(traces).join("\n\n")}`
|
|
|
5980
6246
|
flushNowOrSoon();
|
|
5981
6247
|
}
|
|
5982
6248
|
function dispatchOps(ops) {
|
|
5983
|
-
context.buffer
|
|
6249
|
+
const { storageOperations } = context.buffer;
|
|
6250
|
+
for (const op of ops) {
|
|
6251
|
+
storageOperations.push(op);
|
|
6252
|
+
}
|
|
5984
6253
|
flushNowOrSoon();
|
|
5985
6254
|
}
|
|
5986
6255
|
let _getStorage$ = null;
|
|
5987
6256
|
let _resolveStoragePromise = null;
|
|
6257
|
+
function processInitialStorage(message) {
|
|
6258
|
+
const unacknowledgedOps = new Map(context.unacknowledgedOps);
|
|
6259
|
+
createOrUpdateRootFromMessage(message, doNotBatchUpdates);
|
|
6260
|
+
applyAndSendOps(unacknowledgedOps, doNotBatchUpdates);
|
|
6261
|
+
_resolveStoragePromise?.();
|
|
6262
|
+
notifyStorageStatus();
|
|
6263
|
+
eventHub.storageDidLoad.notify();
|
|
6264
|
+
}
|
|
6265
|
+
async function streamStorage() {
|
|
6266
|
+
if (!managedSocket.authValue) {
|
|
6267
|
+
return;
|
|
6268
|
+
}
|
|
6269
|
+
const result = await streamFetch(managedSocket.authValue, config.roomId);
|
|
6270
|
+
const items = await result.json();
|
|
6271
|
+
processInitialStorage({ type: 200 /* INITIAL_STORAGE_STATE */, items });
|
|
6272
|
+
}
|
|
5988
6273
|
function refreshStorage(options2) {
|
|
5989
6274
|
const messages = context.buffer.messages;
|
|
5990
|
-
if (
|
|
6275
|
+
if (config.unstable_streamData) {
|
|
6276
|
+
void streamStorage();
|
|
6277
|
+
} else if (!messages.some((msg) => msg.type === 200 /* FETCH_STORAGE */)) {
|
|
5991
6278
|
messages.push({ type: 200 /* FETCH_STORAGE */ });
|
|
5992
6279
|
}
|
|
5993
6280
|
if (options2.flush) {
|
|
@@ -6165,372 +6452,1303 @@ ${Array.from(traces).join("\n\n")}`
|
|
|
6165
6452
|
ydoc: eventHub.ydoc.observable,
|
|
6166
6453
|
comments: eventHub.comments.observable
|
|
6167
6454
|
};
|
|
6168
|
-
const commentsApi = createCommentsApi(
|
|
6169
|
-
|
|
6455
|
+
const commentsApi = createCommentsApi(
|
|
6456
|
+
config.roomId,
|
|
6457
|
+
delegates.authenticate,
|
|
6458
|
+
fetchClientApi
|
|
6459
|
+
);
|
|
6460
|
+
async function fetchNotificationsJson(endpoint, options2) {
|
|
6461
|
+
const authValue = await delegates.authenticate();
|
|
6462
|
+
const response = await fetchClientApi(
|
|
6463
|
+
config.roomId,
|
|
6464
|
+
endpoint,
|
|
6465
|
+
authValue,
|
|
6466
|
+
options2
|
|
6467
|
+
);
|
|
6468
|
+
if (!response.ok) {
|
|
6469
|
+
if (response.status >= 400 && response.status < 600) {
|
|
6470
|
+
let error3;
|
|
6471
|
+
try {
|
|
6472
|
+
const errorBody = await response.json();
|
|
6473
|
+
error3 = new NotificationsApiError(
|
|
6474
|
+
errorBody.message,
|
|
6475
|
+
response.status,
|
|
6476
|
+
errorBody
|
|
6477
|
+
);
|
|
6478
|
+
} catch {
|
|
6479
|
+
error3 = new NotificationsApiError(
|
|
6480
|
+
response.statusText,
|
|
6481
|
+
response.status
|
|
6482
|
+
);
|
|
6483
|
+
}
|
|
6484
|
+
throw error3;
|
|
6485
|
+
}
|
|
6486
|
+
}
|
|
6487
|
+
let body;
|
|
6488
|
+
try {
|
|
6489
|
+
body = await response.json();
|
|
6490
|
+
} catch {
|
|
6491
|
+
body = {};
|
|
6492
|
+
}
|
|
6493
|
+
return body;
|
|
6494
|
+
}
|
|
6495
|
+
function getRoomNotificationSettings() {
|
|
6496
|
+
return fetchNotificationsJson(
|
|
6497
|
+
"/notification-settings"
|
|
6498
|
+
);
|
|
6499
|
+
}
|
|
6500
|
+
function updateRoomNotificationSettings(settings) {
|
|
6501
|
+
return fetchNotificationsJson(
|
|
6502
|
+
"/notification-settings",
|
|
6503
|
+
{
|
|
6504
|
+
method: "POST",
|
|
6505
|
+
body: JSON.stringify(settings),
|
|
6506
|
+
headers: {
|
|
6507
|
+
"Content-Type": "application/json"
|
|
6508
|
+
}
|
|
6509
|
+
}
|
|
6510
|
+
);
|
|
6511
|
+
}
|
|
6512
|
+
async function markInboxNotificationsAsRead(inboxNotificationIds) {
|
|
6513
|
+
await fetchNotificationsJson("/inbox-notifications/read", {
|
|
6514
|
+
method: "POST",
|
|
6515
|
+
headers: {
|
|
6516
|
+
"Content-Type": "application/json"
|
|
6517
|
+
},
|
|
6518
|
+
body: JSON.stringify({ inboxNotificationIds })
|
|
6519
|
+
});
|
|
6520
|
+
}
|
|
6521
|
+
const batchedMarkInboxNotificationsAsRead = new Batch(
|
|
6522
|
+
async (batchedInboxNotificationIds) => {
|
|
6523
|
+
const inboxNotificationIds = batchedInboxNotificationIds.flat();
|
|
6524
|
+
await markInboxNotificationsAsRead(inboxNotificationIds);
|
|
6525
|
+
return inboxNotificationIds;
|
|
6526
|
+
},
|
|
6527
|
+
{ delay: MARK_INBOX_NOTIFICATIONS_AS_READ_BATCH_DELAY2 }
|
|
6528
|
+
);
|
|
6529
|
+
async function markInboxNotificationAsRead(inboxNotificationId) {
|
|
6530
|
+
await batchedMarkInboxNotificationsAsRead.get(inboxNotificationId);
|
|
6531
|
+
}
|
|
6532
|
+
return Object.defineProperty(
|
|
6533
|
+
{
|
|
6534
|
+
[kInternal]: {
|
|
6535
|
+
get presenceBuffer() {
|
|
6536
|
+
return deepClone(context.buffer.presenceUpdates?.data ?? null);
|
|
6537
|
+
},
|
|
6538
|
+
// prettier-ignore
|
|
6539
|
+
get undoStack() {
|
|
6540
|
+
return deepClone(context.undoStack);
|
|
6541
|
+
},
|
|
6542
|
+
// prettier-ignore
|
|
6543
|
+
get nodeCount() {
|
|
6544
|
+
return context.nodes.size;
|
|
6545
|
+
},
|
|
6546
|
+
// prettier-ignore
|
|
6547
|
+
// send metadata when using a text editor
|
|
6548
|
+
reportTextEditor,
|
|
6549
|
+
// create a text mention when using a text editor
|
|
6550
|
+
createTextMention,
|
|
6551
|
+
// delete a text mention when using a text editor
|
|
6552
|
+
deleteTextMention,
|
|
6553
|
+
// Support for the Liveblocks browser extension
|
|
6554
|
+
getSelf_forDevTools: () => selfAsTreeNode.current,
|
|
6555
|
+
getOthers_forDevTools: () => others_forDevTools.current,
|
|
6556
|
+
// prettier-ignore
|
|
6557
|
+
simulate: {
|
|
6558
|
+
// These exist only for our E2E testing app
|
|
6559
|
+
explicitClose: (event) => managedSocket._privateSendMachineEvent({ type: "EXPLICIT_SOCKET_CLOSE", event }),
|
|
6560
|
+
rawSend: (data) => managedSocket.send(data)
|
|
6561
|
+
},
|
|
6562
|
+
comments: {
|
|
6563
|
+
...commentsApi
|
|
6564
|
+
},
|
|
6565
|
+
notifications: {
|
|
6566
|
+
getRoomNotificationSettings,
|
|
6567
|
+
updateRoomNotificationSettings,
|
|
6568
|
+
markInboxNotificationAsRead
|
|
6569
|
+
}
|
|
6570
|
+
},
|
|
6571
|
+
id: config.roomId,
|
|
6572
|
+
subscribe: makeClassicSubscribeFn(events),
|
|
6573
|
+
connect: () => managedSocket.connect(),
|
|
6574
|
+
reconnect: () => managedSocket.reconnect(),
|
|
6575
|
+
disconnect: () => managedSocket.disconnect(),
|
|
6576
|
+
destroy: () => {
|
|
6577
|
+
uninstallBgTabSpy();
|
|
6578
|
+
managedSocket.destroy();
|
|
6579
|
+
},
|
|
6580
|
+
// Presence
|
|
6581
|
+
updatePresence,
|
|
6582
|
+
updateYDoc,
|
|
6583
|
+
broadcastEvent,
|
|
6584
|
+
// Storage
|
|
6585
|
+
batch,
|
|
6586
|
+
history: {
|
|
6587
|
+
undo,
|
|
6588
|
+
redo,
|
|
6589
|
+
canUndo,
|
|
6590
|
+
canRedo,
|
|
6591
|
+
clear,
|
|
6592
|
+
pause: pauseHistory,
|
|
6593
|
+
resume: resumeHistory
|
|
6594
|
+
},
|
|
6595
|
+
fetchYDoc,
|
|
6596
|
+
getStorage,
|
|
6597
|
+
getStorageSnapshot,
|
|
6598
|
+
getStorageStatus,
|
|
6599
|
+
events,
|
|
6600
|
+
// Core
|
|
6601
|
+
getStatus: () => managedSocket.getStatus(),
|
|
6602
|
+
getSelf: () => self.current,
|
|
6603
|
+
// Presence
|
|
6604
|
+
getPresence: () => context.myPresence.current,
|
|
6605
|
+
getOthers: () => context.others.current
|
|
6606
|
+
},
|
|
6607
|
+
// Explictly make the internal field non-enumerable, to avoid aggressive
|
|
6608
|
+
// freezing when used with Immer
|
|
6609
|
+
kInternal,
|
|
6610
|
+
{ enumerable: false }
|
|
6611
|
+
);
|
|
6612
|
+
}
|
|
6613
|
+
function makeClassicSubscribeFn(events) {
|
|
6614
|
+
function subscribeToLiveStructureDeeply(node, callback) {
|
|
6615
|
+
return events.storage.subscribe((updates) => {
|
|
6616
|
+
const relatedUpdates = updates.filter(
|
|
6617
|
+
(update) => isSameNodeOrChildOf(update.node, node)
|
|
6618
|
+
);
|
|
6619
|
+
if (relatedUpdates.length > 0) {
|
|
6620
|
+
callback(relatedUpdates);
|
|
6621
|
+
}
|
|
6622
|
+
});
|
|
6623
|
+
}
|
|
6624
|
+
function subscribeToLiveStructureShallowly(node, callback) {
|
|
6625
|
+
return events.storage.subscribe((updates) => {
|
|
6626
|
+
for (const update of updates) {
|
|
6627
|
+
if (update.node._id === node._id) {
|
|
6628
|
+
callback(update.node);
|
|
6629
|
+
}
|
|
6630
|
+
}
|
|
6631
|
+
});
|
|
6632
|
+
}
|
|
6633
|
+
function subscribe(first, second, options) {
|
|
6634
|
+
if (typeof first === "string" && isRoomEventName(first)) {
|
|
6635
|
+
if (typeof second !== "function") {
|
|
6636
|
+
throw new Error("Second argument must be a callback function");
|
|
6637
|
+
}
|
|
6638
|
+
const callback = second;
|
|
6639
|
+
switch (first) {
|
|
6640
|
+
case "event":
|
|
6641
|
+
return events.customEvent.subscribe(
|
|
6642
|
+
callback
|
|
6643
|
+
);
|
|
6644
|
+
case "my-presence":
|
|
6645
|
+
return events.myPresence.subscribe(callback);
|
|
6646
|
+
case "others": {
|
|
6647
|
+
const cb = callback;
|
|
6648
|
+
return events.others.subscribe((event) => {
|
|
6649
|
+
const { others, ...internalEvent } = event;
|
|
6650
|
+
return cb(others, internalEvent);
|
|
6651
|
+
});
|
|
6652
|
+
}
|
|
6653
|
+
case "error":
|
|
6654
|
+
return events.error.subscribe(callback);
|
|
6655
|
+
case "status":
|
|
6656
|
+
return events.status.subscribe(callback);
|
|
6657
|
+
case "lost-connection":
|
|
6658
|
+
return events.lostConnection.subscribe(
|
|
6659
|
+
callback
|
|
6660
|
+
);
|
|
6661
|
+
case "history":
|
|
6662
|
+
return events.history.subscribe(callback);
|
|
6663
|
+
case "storage-status":
|
|
6664
|
+
return events.storageStatus.subscribe(
|
|
6665
|
+
callback
|
|
6666
|
+
);
|
|
6667
|
+
default:
|
|
6668
|
+
return assertNever(
|
|
6669
|
+
first,
|
|
6670
|
+
`"${String(first)}" is not a valid event name`
|
|
6671
|
+
);
|
|
6672
|
+
}
|
|
6673
|
+
}
|
|
6674
|
+
if (second === void 0 || typeof first === "function") {
|
|
6675
|
+
if (typeof first === "function") {
|
|
6676
|
+
const storageCallback = first;
|
|
6677
|
+
return events.storage.subscribe(storageCallback);
|
|
6678
|
+
} else {
|
|
6679
|
+
throw new Error("Please specify a listener callback");
|
|
6680
|
+
}
|
|
6681
|
+
}
|
|
6682
|
+
if (isLiveNode(first)) {
|
|
6683
|
+
const node = first;
|
|
6684
|
+
if (options?.isDeep) {
|
|
6685
|
+
const storageCallback = second;
|
|
6686
|
+
return subscribeToLiveStructureDeeply(node, storageCallback);
|
|
6687
|
+
} else {
|
|
6688
|
+
const nodeCallback = second;
|
|
6689
|
+
return subscribeToLiveStructureShallowly(node, nodeCallback);
|
|
6690
|
+
}
|
|
6691
|
+
}
|
|
6692
|
+
throw new Error(
|
|
6693
|
+
`${String(first)} is not a value that can be subscribed to.`
|
|
6694
|
+
);
|
|
6695
|
+
}
|
|
6696
|
+
return subscribe;
|
|
6697
|
+
}
|
|
6698
|
+
function isRoomEventName(value) {
|
|
6699
|
+
return value === "my-presence" || value === "others" || value === "event" || value === "error" || value === "history" || value === "status" || value === "storage-status" || value === "lost-connection" || value === "connection";
|
|
6700
|
+
}
|
|
6701
|
+
function makeAuthDelegateForRoom(roomId, authManager) {
|
|
6702
|
+
return async () => {
|
|
6703
|
+
return authManager.getAuthValue({ requestedScope: "room:read", roomId });
|
|
6704
|
+
};
|
|
6705
|
+
}
|
|
6706
|
+
function makeCreateSocketDelegateForRoom(roomId, baseUrl, WebSocketPolyfill) {
|
|
6707
|
+
return (authValue) => {
|
|
6708
|
+
const ws = WebSocketPolyfill ?? (typeof WebSocket === "undefined" ? void 0 : WebSocket);
|
|
6709
|
+
if (ws === void 0) {
|
|
6710
|
+
throw new StopRetrying(
|
|
6711
|
+
"To use Liveblocks client in a non-DOM environment, you need to provide a WebSocket polyfill."
|
|
6712
|
+
);
|
|
6713
|
+
}
|
|
6714
|
+
const url = new URL(baseUrl);
|
|
6715
|
+
url.protocol = url.protocol === "http:" ? "ws" : "wss";
|
|
6716
|
+
url.pathname = "/v7";
|
|
6717
|
+
url.searchParams.set("roomId", roomId);
|
|
6718
|
+
if (authValue.type === "secret") {
|
|
6719
|
+
url.searchParams.set("tok", authValue.token.raw);
|
|
6720
|
+
} else if (authValue.type === "public") {
|
|
6721
|
+
url.searchParams.set("pubkey", authValue.publicApiKey);
|
|
6722
|
+
} else {
|
|
6723
|
+
return assertNever(authValue, "Unhandled case");
|
|
6724
|
+
}
|
|
6725
|
+
url.searchParams.set("version", PKG_VERSION || "dev");
|
|
6726
|
+
return new ws(url.toString());
|
|
6727
|
+
};
|
|
6728
|
+
}
|
|
6729
|
+
|
|
6730
|
+
// src/store.ts
|
|
6731
|
+
function createClientStore() {
|
|
6732
|
+
const store = createStore({
|
|
6733
|
+
threads: {},
|
|
6734
|
+
queries: {},
|
|
6735
|
+
optimisticUpdates: [],
|
|
6736
|
+
inboxNotifications: {},
|
|
6737
|
+
notificationSettings: {}
|
|
6738
|
+
});
|
|
6739
|
+
const optimisticUpdatesEventSource = makeEventSource();
|
|
6740
|
+
return {
|
|
6741
|
+
...store,
|
|
6742
|
+
deleteThread(threadId) {
|
|
6743
|
+
store.set((state) => {
|
|
6744
|
+
return {
|
|
6745
|
+
...state,
|
|
6746
|
+
threads: deleteKeyImmutable(state.threads, threadId),
|
|
6747
|
+
inboxNotifications: Object.fromEntries(
|
|
6748
|
+
Object.entries(state.inboxNotifications).filter(
|
|
6749
|
+
([_id, notification]) => notification.kind === "thread" && notification.threadId === threadId
|
|
6750
|
+
)
|
|
6751
|
+
)
|
|
6752
|
+
};
|
|
6753
|
+
});
|
|
6754
|
+
},
|
|
6755
|
+
updateThreadAndNotification(thread, inboxNotification) {
|
|
6756
|
+
store.set((state) => {
|
|
6757
|
+
const existingThread = state.threads[thread.id];
|
|
6758
|
+
return {
|
|
6759
|
+
...state,
|
|
6760
|
+
threads: existingThread === void 0 || compareThreads(thread, existingThread) === 1 ? { ...state.threads, [thread.id]: thread } : state.threads,
|
|
6761
|
+
inboxNotifications: inboxNotification === void 0 ? state.inboxNotifications : {
|
|
6762
|
+
...state.inboxNotifications,
|
|
6763
|
+
[inboxNotification.id]: inboxNotification
|
|
6764
|
+
}
|
|
6765
|
+
};
|
|
6766
|
+
});
|
|
6767
|
+
},
|
|
6768
|
+
updateThreadsAndNotifications(threads, inboxNotifications, deletedThreads, deletedInboxNotifications, queryKey) {
|
|
6769
|
+
store.set((state) => ({
|
|
6770
|
+
...state,
|
|
6771
|
+
threads: applyThreadUpdates(state.threads, {
|
|
6772
|
+
newThreads: threads,
|
|
6773
|
+
deletedThreads
|
|
6774
|
+
}),
|
|
6775
|
+
inboxNotifications: applyNotificationsUpdates(
|
|
6776
|
+
state.inboxNotifications,
|
|
6777
|
+
{
|
|
6778
|
+
newInboxNotifications: inboxNotifications,
|
|
6779
|
+
deletedNotifications: deletedInboxNotifications
|
|
6780
|
+
}
|
|
6781
|
+
),
|
|
6782
|
+
queries: queryKey !== void 0 ? {
|
|
6783
|
+
...state.queries,
|
|
6784
|
+
[queryKey]: {
|
|
6785
|
+
isLoading: false
|
|
6786
|
+
}
|
|
6787
|
+
} : state.queries
|
|
6788
|
+
}));
|
|
6789
|
+
},
|
|
6790
|
+
updateRoomInboxNotificationSettings(roomId, settings, queryKey) {
|
|
6791
|
+
store.set((state) => ({
|
|
6792
|
+
...state,
|
|
6793
|
+
notificationSettings: {
|
|
6794
|
+
...state.notificationSettings,
|
|
6795
|
+
[roomId]: settings
|
|
6796
|
+
},
|
|
6797
|
+
queries: {
|
|
6798
|
+
...state.queries,
|
|
6799
|
+
[queryKey]: {
|
|
6800
|
+
isLoading: false
|
|
6801
|
+
}
|
|
6802
|
+
}
|
|
6803
|
+
}));
|
|
6804
|
+
},
|
|
6805
|
+
pushOptimisticUpdate(optimisticUpdate) {
|
|
6806
|
+
optimisticUpdatesEventSource.notify(optimisticUpdate);
|
|
6807
|
+
store.set((state) => ({
|
|
6808
|
+
...state,
|
|
6809
|
+
optimisticUpdates: [...state.optimisticUpdates, optimisticUpdate]
|
|
6810
|
+
}));
|
|
6811
|
+
},
|
|
6812
|
+
setQueryState(queryKey, queryState) {
|
|
6813
|
+
store.set((state) => ({
|
|
6814
|
+
...state,
|
|
6815
|
+
queries: {
|
|
6816
|
+
...state.queries,
|
|
6817
|
+
[queryKey]: queryState
|
|
6818
|
+
}
|
|
6819
|
+
}));
|
|
6820
|
+
},
|
|
6821
|
+
optimisticUpdatesEventSource
|
|
6822
|
+
};
|
|
6823
|
+
}
|
|
6824
|
+
function deleteKeyImmutable(record, key) {
|
|
6825
|
+
if (Object.prototype.hasOwnProperty.call(record, key)) {
|
|
6826
|
+
const { [key]: _toDelete, ...rest } = record;
|
|
6827
|
+
return rest;
|
|
6828
|
+
}
|
|
6829
|
+
return record;
|
|
6830
|
+
}
|
|
6831
|
+
function compareThreads(thread1, thread2) {
|
|
6832
|
+
if (thread1.updatedAt && thread2.updatedAt) {
|
|
6833
|
+
return thread1.updatedAt > thread2.updatedAt ? 1 : thread1.updatedAt < thread2.updatedAt ? -1 : 0;
|
|
6834
|
+
} else if (thread1.updatedAt || thread2.updatedAt) {
|
|
6835
|
+
return thread1.updatedAt ? 1 : -1;
|
|
6836
|
+
}
|
|
6837
|
+
if (thread1.createdAt > thread2.createdAt) {
|
|
6838
|
+
return 1;
|
|
6839
|
+
} else if (thread1.createdAt < thread2.createdAt) {
|
|
6840
|
+
return -1;
|
|
6841
|
+
}
|
|
6842
|
+
return 0;
|
|
6843
|
+
}
|
|
6844
|
+
function applyOptimisticUpdates(state) {
|
|
6845
|
+
const result = {
|
|
6846
|
+
threads: {
|
|
6847
|
+
...state.threads
|
|
6848
|
+
},
|
|
6849
|
+
inboxNotifications: {
|
|
6850
|
+
...state.inboxNotifications
|
|
6851
|
+
},
|
|
6852
|
+
notificationSettings: {
|
|
6853
|
+
...state.notificationSettings
|
|
6854
|
+
}
|
|
6855
|
+
};
|
|
6856
|
+
for (const optimisticUpdate of state.optimisticUpdates) {
|
|
6857
|
+
switch (optimisticUpdate.type) {
|
|
6858
|
+
case "create-thread": {
|
|
6859
|
+
result.threads[optimisticUpdate.thread.id] = optimisticUpdate.thread;
|
|
6860
|
+
break;
|
|
6861
|
+
}
|
|
6862
|
+
case "edit-thread-metadata": {
|
|
6863
|
+
const thread = result.threads[optimisticUpdate.threadId];
|
|
6864
|
+
if (thread === void 0) {
|
|
6865
|
+
break;
|
|
6866
|
+
}
|
|
6867
|
+
if (thread.deletedAt !== void 0) {
|
|
6868
|
+
break;
|
|
6869
|
+
}
|
|
6870
|
+
if (thread.updatedAt !== void 0 && thread.updatedAt > optimisticUpdate.updatedAt) {
|
|
6871
|
+
break;
|
|
6872
|
+
}
|
|
6873
|
+
result.threads[thread.id] = {
|
|
6874
|
+
...thread,
|
|
6875
|
+
updatedAt: optimisticUpdate.updatedAt,
|
|
6876
|
+
metadata: {
|
|
6877
|
+
...thread.metadata,
|
|
6878
|
+
...optimisticUpdate.metadata
|
|
6879
|
+
}
|
|
6880
|
+
};
|
|
6881
|
+
break;
|
|
6882
|
+
}
|
|
6883
|
+
case "create-comment": {
|
|
6884
|
+
const thread = result.threads[optimisticUpdate.comment.threadId];
|
|
6885
|
+
if (thread === void 0) {
|
|
6886
|
+
break;
|
|
6887
|
+
}
|
|
6888
|
+
result.threads[thread.id] = upsertComment(
|
|
6889
|
+
thread,
|
|
6890
|
+
optimisticUpdate.comment
|
|
6891
|
+
);
|
|
6892
|
+
const inboxNotification = Object.values(result.inboxNotifications).find(
|
|
6893
|
+
(notification) => notification.kind === "thread" && notification.threadId === thread.id
|
|
6894
|
+
);
|
|
6895
|
+
if (inboxNotification === void 0) {
|
|
6896
|
+
break;
|
|
6897
|
+
}
|
|
6898
|
+
result.inboxNotifications[inboxNotification.id] = {
|
|
6899
|
+
...inboxNotification,
|
|
6900
|
+
notifiedAt: optimisticUpdate.comment.createdAt,
|
|
6901
|
+
readAt: optimisticUpdate.comment.createdAt
|
|
6902
|
+
};
|
|
6903
|
+
break;
|
|
6904
|
+
}
|
|
6905
|
+
case "edit-comment": {
|
|
6906
|
+
const thread = result.threads[optimisticUpdate.comment.threadId];
|
|
6907
|
+
if (thread === void 0) {
|
|
6908
|
+
break;
|
|
6909
|
+
}
|
|
6910
|
+
result.threads[thread.id] = upsertComment(
|
|
6911
|
+
thread,
|
|
6912
|
+
optimisticUpdate.comment
|
|
6913
|
+
);
|
|
6914
|
+
break;
|
|
6915
|
+
}
|
|
6916
|
+
case "delete-comment": {
|
|
6917
|
+
const thread = result.threads[optimisticUpdate.threadId];
|
|
6918
|
+
if (thread === void 0) {
|
|
6919
|
+
break;
|
|
6920
|
+
}
|
|
6921
|
+
result.threads[thread.id] = deleteComment(
|
|
6922
|
+
thread,
|
|
6923
|
+
optimisticUpdate.commentId,
|
|
6924
|
+
optimisticUpdate.deletedAt
|
|
6925
|
+
);
|
|
6926
|
+
break;
|
|
6927
|
+
}
|
|
6928
|
+
case "add-reaction": {
|
|
6929
|
+
const thread = result.threads[optimisticUpdate.threadId];
|
|
6930
|
+
if (thread === void 0) {
|
|
6931
|
+
break;
|
|
6932
|
+
}
|
|
6933
|
+
result.threads[thread.id] = addReaction(
|
|
6934
|
+
thread,
|
|
6935
|
+
optimisticUpdate.commentId,
|
|
6936
|
+
optimisticUpdate.reaction
|
|
6937
|
+
);
|
|
6938
|
+
break;
|
|
6939
|
+
}
|
|
6940
|
+
case "remove-reaction": {
|
|
6941
|
+
const thread = result.threads[optimisticUpdate.threadId];
|
|
6942
|
+
if (thread === void 0) {
|
|
6943
|
+
break;
|
|
6944
|
+
}
|
|
6945
|
+
result.threads[thread.id] = removeReaction(
|
|
6946
|
+
thread,
|
|
6947
|
+
optimisticUpdate.commentId,
|
|
6948
|
+
optimisticUpdate.emoji,
|
|
6949
|
+
optimisticUpdate.userId,
|
|
6950
|
+
optimisticUpdate.removedAt
|
|
6951
|
+
);
|
|
6952
|
+
break;
|
|
6953
|
+
}
|
|
6954
|
+
case "mark-inbox-notification-as-read": {
|
|
6955
|
+
result.inboxNotifications[optimisticUpdate.inboxNotificationId] = {
|
|
6956
|
+
...state.inboxNotifications[optimisticUpdate.inboxNotificationId],
|
|
6957
|
+
readAt: optimisticUpdate.readAt
|
|
6958
|
+
};
|
|
6959
|
+
break;
|
|
6960
|
+
}
|
|
6961
|
+
case "mark-inbox-notifications-as-read": {
|
|
6962
|
+
for (const id in result.inboxNotifications) {
|
|
6963
|
+
result.inboxNotifications[id] = {
|
|
6964
|
+
...result.inboxNotifications[id],
|
|
6965
|
+
readAt: optimisticUpdate.readAt
|
|
6966
|
+
};
|
|
6967
|
+
}
|
|
6968
|
+
break;
|
|
6969
|
+
}
|
|
6970
|
+
case "update-notification-settings": {
|
|
6971
|
+
result.notificationSettings[optimisticUpdate.roomId] = {
|
|
6972
|
+
...result.notificationSettings[optimisticUpdate.roomId],
|
|
6973
|
+
...optimisticUpdate.settings
|
|
6974
|
+
};
|
|
6975
|
+
}
|
|
6976
|
+
}
|
|
6977
|
+
}
|
|
6978
|
+
return result;
|
|
6979
|
+
}
|
|
6980
|
+
function applyThreadUpdates(existingThreads, updates) {
|
|
6981
|
+
const updatedThreads = { ...existingThreads };
|
|
6982
|
+
updates.newThreads.forEach((thread) => {
|
|
6983
|
+
const existingThread = updatedThreads[thread.id];
|
|
6984
|
+
if (existingThread) {
|
|
6985
|
+
const result = compareThreads(existingThread, thread);
|
|
6986
|
+
if (result === 1) return;
|
|
6987
|
+
}
|
|
6988
|
+
updatedThreads[thread.id] = thread;
|
|
6989
|
+
});
|
|
6990
|
+
updates.deletedThreads.forEach(({ id, deletedAt }) => {
|
|
6991
|
+
const existingThread = updatedThreads[id];
|
|
6992
|
+
if (existingThread === void 0) return;
|
|
6993
|
+
existingThread.deletedAt = deletedAt;
|
|
6994
|
+
existingThread.updatedAt = deletedAt;
|
|
6995
|
+
existingThread.comments = [];
|
|
6996
|
+
});
|
|
6997
|
+
return updatedThreads;
|
|
6998
|
+
}
|
|
6999
|
+
function applyNotificationsUpdates(existingInboxNotifications, updates) {
|
|
7000
|
+
const updatedInboxNotifications = { ...existingInboxNotifications };
|
|
7001
|
+
updates.newInboxNotifications.forEach((notification) => {
|
|
7002
|
+
const existingNotification = updatedInboxNotifications[notification.id];
|
|
7003
|
+
if (existingNotification) {
|
|
7004
|
+
const result = compareInboxNotifications(
|
|
7005
|
+
existingNotification,
|
|
7006
|
+
notification
|
|
7007
|
+
);
|
|
7008
|
+
if (result === 1) return;
|
|
7009
|
+
}
|
|
7010
|
+
updatedInboxNotifications[notification.id] = notification;
|
|
7011
|
+
});
|
|
7012
|
+
updates.deletedNotifications.forEach(
|
|
7013
|
+
({ id }) => delete updatedInboxNotifications[id]
|
|
7014
|
+
);
|
|
7015
|
+
return updatedInboxNotifications;
|
|
7016
|
+
}
|
|
7017
|
+
function compareInboxNotifications(inboxNotificationA, inboxNotificationB) {
|
|
7018
|
+
if (inboxNotificationA.notifiedAt > inboxNotificationB.notifiedAt) {
|
|
7019
|
+
return 1;
|
|
7020
|
+
} else if (inboxNotificationA.notifiedAt < inboxNotificationB.notifiedAt) {
|
|
7021
|
+
return -1;
|
|
7022
|
+
}
|
|
7023
|
+
if (inboxNotificationA.readAt && inboxNotificationB.readAt) {
|
|
7024
|
+
return inboxNotificationA.readAt > inboxNotificationB.readAt ? 1 : inboxNotificationA.readAt < inboxNotificationB.readAt ? -1 : 0;
|
|
7025
|
+
} else if (inboxNotificationA.readAt || inboxNotificationB.readAt) {
|
|
7026
|
+
return inboxNotificationA.readAt ? 1 : -1;
|
|
7027
|
+
}
|
|
7028
|
+
return 0;
|
|
7029
|
+
}
|
|
7030
|
+
function upsertComment(thread, comment) {
|
|
7031
|
+
if (thread.deletedAt !== void 0) {
|
|
7032
|
+
return thread;
|
|
7033
|
+
}
|
|
7034
|
+
if (comment.threadId !== thread.id) {
|
|
7035
|
+
warn(
|
|
7036
|
+
`Comment ${comment.id} does not belong to thread ${thread.id}`
|
|
7037
|
+
);
|
|
7038
|
+
return thread;
|
|
7039
|
+
}
|
|
7040
|
+
const existingComment = thread.comments.find(
|
|
7041
|
+
(existingComment2) => existingComment2.id === comment.id
|
|
7042
|
+
);
|
|
7043
|
+
if (existingComment === void 0) {
|
|
7044
|
+
const updatedAt = new Date(
|
|
7045
|
+
Math.max(thread.updatedAt?.getTime() || 0, comment.createdAt.getTime())
|
|
7046
|
+
);
|
|
7047
|
+
const updatedThread = {
|
|
7048
|
+
...thread,
|
|
7049
|
+
updatedAt,
|
|
7050
|
+
comments: [...thread.comments, comment]
|
|
7051
|
+
};
|
|
7052
|
+
return updatedThread;
|
|
7053
|
+
}
|
|
7054
|
+
if (existingComment.deletedAt !== void 0) {
|
|
7055
|
+
return thread;
|
|
7056
|
+
}
|
|
7057
|
+
if (existingComment.editedAt === void 0 || comment.editedAt === void 0 || existingComment.editedAt <= comment.editedAt) {
|
|
7058
|
+
const updatedComments = thread.comments.map(
|
|
7059
|
+
(existingComment2) => existingComment2.id === comment.id ? comment : existingComment2
|
|
7060
|
+
);
|
|
7061
|
+
const updatedThread = {
|
|
7062
|
+
...thread,
|
|
7063
|
+
updatedAt: new Date(
|
|
7064
|
+
Math.max(
|
|
7065
|
+
thread.updatedAt?.getTime() || 0,
|
|
7066
|
+
comment.editedAt?.getTime() || comment.createdAt.getTime()
|
|
7067
|
+
)
|
|
7068
|
+
),
|
|
7069
|
+
comments: updatedComments
|
|
7070
|
+
};
|
|
7071
|
+
return updatedThread;
|
|
7072
|
+
}
|
|
7073
|
+
return thread;
|
|
7074
|
+
}
|
|
7075
|
+
function deleteComment(thread, commentId, deletedAt) {
|
|
7076
|
+
if (thread.deletedAt !== void 0) {
|
|
7077
|
+
return thread;
|
|
7078
|
+
}
|
|
7079
|
+
const existingComment = thread.comments.find(
|
|
7080
|
+
(comment) => comment.id === commentId
|
|
7081
|
+
);
|
|
7082
|
+
if (existingComment === void 0) {
|
|
7083
|
+
return thread;
|
|
7084
|
+
}
|
|
7085
|
+
if (existingComment.deletedAt !== void 0) {
|
|
7086
|
+
return thread;
|
|
7087
|
+
}
|
|
7088
|
+
const updatedComments = thread.comments.map(
|
|
7089
|
+
(comment) => comment.id === commentId ? {
|
|
7090
|
+
...comment,
|
|
7091
|
+
deletedAt,
|
|
7092
|
+
body: void 0
|
|
7093
|
+
} : comment
|
|
7094
|
+
);
|
|
7095
|
+
if (!updatedComments.some((comment) => comment.deletedAt === void 0)) {
|
|
7096
|
+
return {
|
|
7097
|
+
...thread,
|
|
7098
|
+
deletedAt,
|
|
7099
|
+
updatedAt: deletedAt,
|
|
7100
|
+
comments: []
|
|
7101
|
+
};
|
|
7102
|
+
}
|
|
7103
|
+
return {
|
|
7104
|
+
...thread,
|
|
7105
|
+
updatedAt: deletedAt,
|
|
7106
|
+
comments: updatedComments
|
|
7107
|
+
};
|
|
7108
|
+
}
|
|
7109
|
+
function addReaction(thread, commentId, reaction) {
|
|
7110
|
+
if (thread.deletedAt !== void 0) {
|
|
7111
|
+
return thread;
|
|
7112
|
+
}
|
|
7113
|
+
const existingComment = thread.comments.find(
|
|
7114
|
+
(comment) => comment.id === commentId
|
|
7115
|
+
);
|
|
7116
|
+
if (existingComment === void 0) {
|
|
7117
|
+
return thread;
|
|
7118
|
+
}
|
|
7119
|
+
if (existingComment.deletedAt !== void 0) {
|
|
7120
|
+
return thread;
|
|
7121
|
+
}
|
|
7122
|
+
const updatedComments = thread.comments.map(
|
|
7123
|
+
(comment) => comment.id === commentId ? {
|
|
7124
|
+
...comment,
|
|
7125
|
+
reactions: upsertReaction(comment.reactions, reaction)
|
|
7126
|
+
} : comment
|
|
7127
|
+
);
|
|
7128
|
+
return {
|
|
7129
|
+
...thread,
|
|
7130
|
+
updatedAt: new Date(
|
|
7131
|
+
Math.max(reaction.createdAt.getTime(), thread.updatedAt?.getTime() || 0)
|
|
7132
|
+
),
|
|
7133
|
+
comments: updatedComments
|
|
7134
|
+
};
|
|
7135
|
+
}
|
|
7136
|
+
function removeReaction(thread, commentId, emoji, userId, removedAt) {
|
|
7137
|
+
if (thread.deletedAt !== void 0) {
|
|
7138
|
+
return thread;
|
|
7139
|
+
}
|
|
7140
|
+
const existingComment = thread.comments.find(
|
|
7141
|
+
(comment) => comment.id === commentId
|
|
7142
|
+
);
|
|
7143
|
+
if (existingComment === void 0) {
|
|
7144
|
+
return thread;
|
|
7145
|
+
}
|
|
7146
|
+
if (existingComment.deletedAt !== void 0) {
|
|
7147
|
+
return thread;
|
|
7148
|
+
}
|
|
7149
|
+
const updatedComments = thread.comments.map(
|
|
7150
|
+
(comment) => comment.id === commentId ? {
|
|
7151
|
+
...comment,
|
|
7152
|
+
reactions: comment.reactions.map(
|
|
7153
|
+
(reaction) => reaction.emoji === emoji ? {
|
|
7154
|
+
...reaction,
|
|
7155
|
+
users: reaction.users.filter((user) => user.id !== userId)
|
|
7156
|
+
} : reaction
|
|
7157
|
+
).filter((reaction) => reaction.users.length > 0)
|
|
7158
|
+
// Remove reactions with no users left
|
|
7159
|
+
} : comment
|
|
7160
|
+
);
|
|
7161
|
+
return {
|
|
7162
|
+
...thread,
|
|
7163
|
+
updatedAt: new Date(
|
|
7164
|
+
Math.max(removedAt.getTime(), thread.updatedAt?.getTime() || 0)
|
|
7165
|
+
),
|
|
7166
|
+
comments: updatedComments
|
|
7167
|
+
};
|
|
7168
|
+
}
|
|
7169
|
+
function upsertReaction(reactions, reaction) {
|
|
7170
|
+
const existingReaction = reactions.find(
|
|
7171
|
+
(existingReaction2) => existingReaction2.emoji === reaction.emoji
|
|
7172
|
+
);
|
|
7173
|
+
if (existingReaction === void 0) {
|
|
7174
|
+
return [
|
|
7175
|
+
...reactions,
|
|
7176
|
+
{
|
|
7177
|
+
emoji: reaction.emoji,
|
|
7178
|
+
createdAt: reaction.createdAt,
|
|
7179
|
+
users: [{ id: reaction.userId }]
|
|
7180
|
+
}
|
|
7181
|
+
];
|
|
7182
|
+
}
|
|
7183
|
+
if (existingReaction.users.some((user) => user.id === reaction.userId) === false) {
|
|
7184
|
+
return reactions.map(
|
|
7185
|
+
(existingReaction2) => existingReaction2.emoji === reaction.emoji ? {
|
|
7186
|
+
...existingReaction2,
|
|
7187
|
+
users: [...existingReaction2.users, { id: reaction.userId }]
|
|
7188
|
+
} : existingReaction2
|
|
7189
|
+
);
|
|
7190
|
+
}
|
|
7191
|
+
return reactions;
|
|
7192
|
+
}
|
|
7193
|
+
|
|
7194
|
+
// src/client.ts
|
|
7195
|
+
var MIN_THROTTLE = 16;
|
|
7196
|
+
var MAX_THROTTLE = 1e3;
|
|
7197
|
+
var DEFAULT_THROTTLE = 100;
|
|
7198
|
+
var MIN_BACKGROUND_KEEP_ALIVE_TIMEOUT = 15e3;
|
|
7199
|
+
var MIN_LOST_CONNECTION_TIMEOUT = 200;
|
|
7200
|
+
var RECOMMENDED_MIN_LOST_CONNECTION_TIMEOUT = 1e3;
|
|
7201
|
+
var MAX_LOST_CONNECTION_TIMEOUT = 3e4;
|
|
7202
|
+
var DEFAULT_LOST_CONNECTION_TIMEOUT = 5e3;
|
|
7203
|
+
var RESOLVE_USERS_BATCH_DELAY = 50;
|
|
7204
|
+
var RESOLVE_ROOMS_INFO_BATCH_DELAY = 50;
|
|
7205
|
+
function getBaseUrl(baseUrl) {
|
|
7206
|
+
if (typeof baseUrl === "string" && baseUrl.startsWith("http")) {
|
|
7207
|
+
return baseUrl;
|
|
7208
|
+
} else {
|
|
7209
|
+
return DEFAULT_BASE_URL;
|
|
7210
|
+
}
|
|
7211
|
+
}
|
|
7212
|
+
function getAuthBearerHeaderFromAuthValue(authValue) {
|
|
7213
|
+
if (authValue.type === "public") {
|
|
7214
|
+
return authValue.publicApiKey;
|
|
7215
|
+
} else {
|
|
7216
|
+
return authValue.token.raw;
|
|
7217
|
+
}
|
|
7218
|
+
}
|
|
7219
|
+
function createClient(options) {
|
|
7220
|
+
const clientOptions = options;
|
|
7221
|
+
const throttleDelay = getThrottle(clientOptions.throttle ?? DEFAULT_THROTTLE);
|
|
7222
|
+
const lostConnectionTimeout = getLostConnectionTimeout(
|
|
7223
|
+
clientOptions.lostConnectionTimeout ?? DEFAULT_LOST_CONNECTION_TIMEOUT
|
|
7224
|
+
);
|
|
7225
|
+
const backgroundKeepAliveTimeout = getBackgroundKeepAliveTimeout(
|
|
7226
|
+
clientOptions.backgroundKeepAliveTimeout
|
|
7227
|
+
);
|
|
7228
|
+
const baseUrl = getBaseUrl(clientOptions.baseUrl);
|
|
7229
|
+
const authManager = createAuthManager(options);
|
|
7230
|
+
const roomsById = /* @__PURE__ */ new Map();
|
|
7231
|
+
function teardownRoom(room) {
|
|
7232
|
+
unlinkDevTools(room.id);
|
|
7233
|
+
roomsById.delete(room.id);
|
|
7234
|
+
room.destroy();
|
|
7235
|
+
}
|
|
7236
|
+
function leaseRoom(details) {
|
|
7237
|
+
const leave = () => {
|
|
7238
|
+
const self = leave;
|
|
7239
|
+
if (!details.unsubs.delete(self)) {
|
|
7240
|
+
warn(
|
|
7241
|
+
"This leave function was already called. Calling it more than once has no effect."
|
|
7242
|
+
);
|
|
7243
|
+
} else {
|
|
7244
|
+
if (details.unsubs.size === 0) {
|
|
7245
|
+
teardownRoom(details.room);
|
|
7246
|
+
}
|
|
7247
|
+
}
|
|
7248
|
+
};
|
|
7249
|
+
details.unsubs.add(leave);
|
|
7250
|
+
return {
|
|
7251
|
+
room: details.room,
|
|
7252
|
+
leave
|
|
7253
|
+
};
|
|
7254
|
+
}
|
|
7255
|
+
function enterRoom(roomId, options2) {
|
|
7256
|
+
const existing = roomsById.get(roomId);
|
|
7257
|
+
if (existing !== void 0) {
|
|
7258
|
+
return leaseRoom(existing);
|
|
7259
|
+
}
|
|
7260
|
+
deprecateIf(
|
|
7261
|
+
options2.initialPresence === null || options2.initialPresence === void 0,
|
|
7262
|
+
"Please provide an initial presence value for the current user when entering the room."
|
|
7263
|
+
);
|
|
7264
|
+
const newRoom = createRoom(
|
|
7265
|
+
{
|
|
7266
|
+
initialPresence: options2.initialPresence ?? {},
|
|
7267
|
+
initialStorage: options2.initialStorage
|
|
7268
|
+
},
|
|
7269
|
+
{
|
|
7270
|
+
roomId,
|
|
7271
|
+
throttleDelay,
|
|
7272
|
+
lostConnectionTimeout,
|
|
7273
|
+
backgroundKeepAliveTimeout,
|
|
7274
|
+
polyfills: clientOptions.polyfills,
|
|
7275
|
+
delegates: clientOptions.mockedDelegates ?? {
|
|
7276
|
+
createSocket: makeCreateSocketDelegateForRoom(
|
|
7277
|
+
roomId,
|
|
7278
|
+
baseUrl,
|
|
7279
|
+
clientOptions.polyfills?.WebSocket
|
|
7280
|
+
),
|
|
7281
|
+
authenticate: makeAuthDelegateForRoom(roomId, authManager)
|
|
7282
|
+
},
|
|
7283
|
+
enableDebugLogging: clientOptions.enableDebugLogging,
|
|
7284
|
+
unstable_batchedUpdates: options2?.unstable_batchedUpdates,
|
|
7285
|
+
baseUrl,
|
|
7286
|
+
unstable_fallbackToHTTP: !!clientOptions.unstable_fallbackToHTTP,
|
|
7287
|
+
unstable_streamData: !!clientOptions.unstable_streamData
|
|
7288
|
+
}
|
|
7289
|
+
);
|
|
7290
|
+
const newRoomDetails = {
|
|
7291
|
+
room: newRoom,
|
|
7292
|
+
unsubs: /* @__PURE__ */ new Set()
|
|
7293
|
+
};
|
|
7294
|
+
roomsById.set(roomId, newRoomDetails);
|
|
7295
|
+
setupDevTools(() => Array.from(roomsById.keys()));
|
|
7296
|
+
linkDevTools(roomId, newRoom);
|
|
7297
|
+
const shouldConnect = options2.autoConnect ?? true;
|
|
7298
|
+
if (shouldConnect) {
|
|
7299
|
+
if (typeof atob === "undefined") {
|
|
7300
|
+
if (clientOptions.polyfills?.atob === void 0) {
|
|
7301
|
+
throw new Error(
|
|
7302
|
+
"You need to polyfill atob to use the client in your environment. Please follow the instructions at https://liveblocks.io/docs/errors/liveblocks-client/atob-polyfill"
|
|
7303
|
+
);
|
|
7304
|
+
}
|
|
7305
|
+
global.atob = clientOptions.polyfills.atob;
|
|
7306
|
+
}
|
|
7307
|
+
newRoom.connect();
|
|
7308
|
+
}
|
|
7309
|
+
return leaseRoom(newRoomDetails);
|
|
7310
|
+
}
|
|
7311
|
+
function getRoom(roomId) {
|
|
7312
|
+
const room = roomsById.get(roomId)?.room;
|
|
7313
|
+
return room ? room : null;
|
|
7314
|
+
}
|
|
7315
|
+
function logout() {
|
|
7316
|
+
authManager.reset();
|
|
7317
|
+
for (const { room } of roomsById.values()) {
|
|
7318
|
+
if (!isIdle(room.getStatus())) {
|
|
7319
|
+
room.reconnect();
|
|
7320
|
+
}
|
|
7321
|
+
}
|
|
7322
|
+
}
|
|
7323
|
+
const currentUserIdStore = createStore(null);
|
|
7324
|
+
const {
|
|
7325
|
+
getInboxNotifications,
|
|
7326
|
+
getUnreadInboxNotificationsCount,
|
|
7327
|
+
markAllInboxNotificationsAsRead,
|
|
7328
|
+
markInboxNotificationAsRead
|
|
7329
|
+
} = createNotificationsApi({
|
|
7330
|
+
baseUrl,
|
|
7331
|
+
fetcher: clientOptions.polyfills?.fetch || /* istanbul ignore next */
|
|
7332
|
+
fetch,
|
|
7333
|
+
authManager,
|
|
7334
|
+
currentUserIdStore
|
|
6170
7335
|
});
|
|
7336
|
+
const cacheStore = createClientStore();
|
|
7337
|
+
const resolveUsers = clientOptions.resolveUsers;
|
|
7338
|
+
const warnIfNoResolveUsers = createDevelopmentWarning(
|
|
7339
|
+
() => !resolveUsers,
|
|
7340
|
+
"Set the resolveUsers option in createClient to specify user info."
|
|
7341
|
+
);
|
|
7342
|
+
const usersStore = createBatchStore(
|
|
7343
|
+
async (batchedUserIds) => {
|
|
7344
|
+
const userIds = batchedUserIds.flat();
|
|
7345
|
+
const users = await resolveUsers?.({ userIds });
|
|
7346
|
+
warnIfNoResolveUsers();
|
|
7347
|
+
return users ?? userIds.map(() => void 0);
|
|
7348
|
+
},
|
|
7349
|
+
{ delay: RESOLVE_USERS_BATCH_DELAY }
|
|
7350
|
+
);
|
|
7351
|
+
const resolveRoomsInfo = clientOptions.resolveRoomsInfo;
|
|
7352
|
+
const warnIfNoResolveRoomsInfo = createDevelopmentWarning(
|
|
7353
|
+
() => !resolveRoomsInfo,
|
|
7354
|
+
"Set the resolveRoomsInfo option in createClient to specify room info."
|
|
7355
|
+
);
|
|
7356
|
+
const roomsInfoStore = createBatchStore(
|
|
7357
|
+
async (batchedRoomIds) => {
|
|
7358
|
+
const roomIds = batchedRoomIds.flat();
|
|
7359
|
+
const roomsInfo = await resolveRoomsInfo?.({ roomIds });
|
|
7360
|
+
warnIfNoResolveRoomsInfo();
|
|
7361
|
+
return roomsInfo ?? roomIds.map(() => void 0);
|
|
7362
|
+
},
|
|
7363
|
+
{ delay: RESOLVE_ROOMS_INFO_BATCH_DELAY }
|
|
7364
|
+
);
|
|
6171
7365
|
return Object.defineProperty(
|
|
6172
7366
|
{
|
|
6173
|
-
|
|
6174
|
-
|
|
6175
|
-
|
|
6176
|
-
|
|
6177
|
-
|
|
6178
|
-
|
|
6179
|
-
|
|
6180
|
-
|
|
6181
|
-
|
|
6182
|
-
|
|
6183
|
-
get nodeCount() {
|
|
6184
|
-
return context.nodes.size;
|
|
7367
|
+
enterRoom,
|
|
7368
|
+
getRoom,
|
|
7369
|
+
logout,
|
|
7370
|
+
// Internal
|
|
7371
|
+
[kInternal]: {
|
|
7372
|
+
notifications: {
|
|
7373
|
+
getInboxNotifications,
|
|
7374
|
+
getUnreadInboxNotificationsCount,
|
|
7375
|
+
markAllInboxNotificationsAsRead,
|
|
7376
|
+
markInboxNotificationAsRead
|
|
6185
7377
|
},
|
|
6186
|
-
|
|
6187
|
-
|
|
6188
|
-
|
|
6189
|
-
|
|
6190
|
-
|
|
6191
|
-
|
|
6192
|
-
|
|
6193
|
-
explicitClose: (event) => managedSocket._privateSendMachineEvent({ type: "EXPLICIT_SOCKET_CLOSE", event }),
|
|
6194
|
-
rawSend: (data) => managedSocket.send(data)
|
|
7378
|
+
currentUserIdStore,
|
|
7379
|
+
resolveMentionSuggestions: clientOptions.resolveMentionSuggestions,
|
|
7380
|
+
cacheStore,
|
|
7381
|
+
usersStore,
|
|
7382
|
+
roomsInfoStore,
|
|
7383
|
+
getRoomIds() {
|
|
7384
|
+
return Array.from(roomsById.keys());
|
|
6195
7385
|
}
|
|
6196
|
-
}
|
|
6197
|
-
id: config.roomId,
|
|
6198
|
-
subscribe: makeClassicSubscribeFn(events),
|
|
6199
|
-
connect: () => managedSocket.connect(),
|
|
6200
|
-
reconnect: () => managedSocket.reconnect(),
|
|
6201
|
-
disconnect: () => managedSocket.disconnect(),
|
|
6202
|
-
destroy: () => {
|
|
6203
|
-
uninstallBgTabSpy();
|
|
6204
|
-
managedSocket.destroy();
|
|
6205
|
-
},
|
|
6206
|
-
// Presence
|
|
6207
|
-
updatePresence,
|
|
6208
|
-
updateYDoc,
|
|
6209
|
-
broadcastEvent,
|
|
6210
|
-
// Storage
|
|
6211
|
-
batch,
|
|
6212
|
-
history: {
|
|
6213
|
-
undo,
|
|
6214
|
-
redo,
|
|
6215
|
-
canUndo,
|
|
6216
|
-
canRedo,
|
|
6217
|
-
clear,
|
|
6218
|
-
pause: pauseHistory,
|
|
6219
|
-
resume: resumeHistory
|
|
6220
|
-
},
|
|
6221
|
-
fetchYDoc,
|
|
6222
|
-
getStorage,
|
|
6223
|
-
getStorageSnapshot,
|
|
6224
|
-
getStorageStatus,
|
|
6225
|
-
events,
|
|
6226
|
-
// Core
|
|
6227
|
-
getStatus: () => managedSocket.getStatus(),
|
|
6228
|
-
getConnectionState: () => managedSocket.getLegacyStatus(),
|
|
6229
|
-
getSelf: () => self.current,
|
|
6230
|
-
// Presence
|
|
6231
|
-
getPresence: () => context.myPresence.current,
|
|
6232
|
-
getOthers: () => context.others.current,
|
|
6233
|
-
...commentsApi
|
|
7386
|
+
}
|
|
6234
7387
|
},
|
|
6235
|
-
|
|
6236
|
-
|
|
6237
|
-
|
|
6238
|
-
|
|
7388
|
+
kInternal,
|
|
7389
|
+
{
|
|
7390
|
+
enumerable: false
|
|
7391
|
+
}
|
|
6239
7392
|
);
|
|
6240
7393
|
}
|
|
6241
|
-
|
|
6242
|
-
|
|
6243
|
-
|
|
6244
|
-
|
|
6245
|
-
|
|
6246
|
-
|
|
6247
|
-
if (relatedUpdates.length > 0) {
|
|
6248
|
-
callback(relatedUpdates);
|
|
6249
|
-
}
|
|
6250
|
-
});
|
|
7394
|
+
var NotificationsApiError = class extends Error {
|
|
7395
|
+
constructor(message, status, details) {
|
|
7396
|
+
super(message);
|
|
7397
|
+
this.message = message;
|
|
7398
|
+
this.status = status;
|
|
7399
|
+
this.details = details;
|
|
6251
7400
|
}
|
|
6252
|
-
|
|
6253
|
-
|
|
6254
|
-
|
|
6255
|
-
|
|
6256
|
-
|
|
6257
|
-
|
|
6258
|
-
}
|
|
6259
|
-
});
|
|
7401
|
+
};
|
|
7402
|
+
function checkBounds(option, value, min, max, recommendedMin) {
|
|
7403
|
+
if (typeof value !== "number" || value < min || max !== void 0 && value > max) {
|
|
7404
|
+
throw new Error(
|
|
7405
|
+
max !== void 0 ? `${option} should be between ${recommendedMin ?? min} and ${max}.` : `${option} should be at least ${recommendedMin ?? min}.`
|
|
7406
|
+
);
|
|
6260
7407
|
}
|
|
6261
|
-
|
|
6262
|
-
|
|
6263
|
-
|
|
6264
|
-
|
|
7408
|
+
return value;
|
|
7409
|
+
}
|
|
7410
|
+
function getBackgroundKeepAliveTimeout(value) {
|
|
7411
|
+
if (value === void 0) return void 0;
|
|
7412
|
+
return checkBounds(
|
|
7413
|
+
"backgroundKeepAliveTimeout",
|
|
7414
|
+
value,
|
|
7415
|
+
MIN_BACKGROUND_KEEP_ALIVE_TIMEOUT
|
|
7416
|
+
);
|
|
7417
|
+
}
|
|
7418
|
+
function getThrottle(value) {
|
|
7419
|
+
return checkBounds("throttle", value, MIN_THROTTLE, MAX_THROTTLE);
|
|
7420
|
+
}
|
|
7421
|
+
function getLostConnectionTimeout(value) {
|
|
7422
|
+
return checkBounds(
|
|
7423
|
+
"lostConnectionTimeout",
|
|
7424
|
+
value,
|
|
7425
|
+
MIN_LOST_CONNECTION_TIMEOUT,
|
|
7426
|
+
MAX_LOST_CONNECTION_TIMEOUT,
|
|
7427
|
+
RECOMMENDED_MIN_LOST_CONNECTION_TIMEOUT
|
|
7428
|
+
);
|
|
7429
|
+
}
|
|
7430
|
+
function createDevelopmentWarning(condition, ...args) {
|
|
7431
|
+
let hasWarned = false;
|
|
7432
|
+
if (process.env.NODE_ENV !== "production") {
|
|
7433
|
+
return () => {
|
|
7434
|
+
if (!hasWarned && (typeof condition === "function" ? condition() : condition)) {
|
|
7435
|
+
warn(...args);
|
|
7436
|
+
hasWarned = true;
|
|
6265
7437
|
}
|
|
6266
|
-
|
|
6267
|
-
|
|
6268
|
-
|
|
6269
|
-
|
|
6270
|
-
|
|
6271
|
-
|
|
6272
|
-
|
|
6273
|
-
|
|
6274
|
-
|
|
6275
|
-
|
|
6276
|
-
|
|
6277
|
-
|
|
6278
|
-
|
|
6279
|
-
|
|
6280
|
-
|
|
6281
|
-
|
|
6282
|
-
|
|
6283
|
-
|
|
6284
|
-
|
|
6285
|
-
|
|
6286
|
-
|
|
6287
|
-
|
|
6288
|
-
|
|
6289
|
-
|
|
6290
|
-
|
|
6291
|
-
|
|
6292
|
-
|
|
6293
|
-
|
|
6294
|
-
|
|
6295
|
-
|
|
6296
|
-
|
|
6297
|
-
|
|
6298
|
-
|
|
6299
|
-
|
|
6300
|
-
|
|
6301
|
-
|
|
6302
|
-
|
|
6303
|
-
|
|
6304
|
-
|
|
6305
|
-
|
|
7438
|
+
};
|
|
7439
|
+
} else {
|
|
7440
|
+
return () => {
|
|
7441
|
+
};
|
|
7442
|
+
}
|
|
7443
|
+
}
|
|
7444
|
+
|
|
7445
|
+
// src/comments/comment-body.ts
|
|
7446
|
+
function isCommentBodyParagraph(element) {
|
|
7447
|
+
return "type" in element && element.type === "mention";
|
|
7448
|
+
}
|
|
7449
|
+
function isCommentBodyText(element) {
|
|
7450
|
+
return "text" in element && typeof element.text === "string";
|
|
7451
|
+
}
|
|
7452
|
+
function isCommentBodyMention(element) {
|
|
7453
|
+
return "type" in element && element.type === "mention";
|
|
7454
|
+
}
|
|
7455
|
+
function isCommentBodyLink(element) {
|
|
7456
|
+
return "type" in element && element.type === "link";
|
|
7457
|
+
}
|
|
7458
|
+
var commentBodyElementsGuards = {
|
|
7459
|
+
paragraph: isCommentBodyParagraph,
|
|
7460
|
+
text: isCommentBodyText,
|
|
7461
|
+
link: isCommentBodyLink,
|
|
7462
|
+
mention: isCommentBodyMention
|
|
7463
|
+
};
|
|
7464
|
+
var commentBodyElementsTypes = {
|
|
7465
|
+
paragraph: "block",
|
|
7466
|
+
text: "inline",
|
|
7467
|
+
link: "inline",
|
|
7468
|
+
mention: "inline"
|
|
7469
|
+
};
|
|
7470
|
+
function traverseCommentBody(body, elementOrVisitor, possiblyVisitor) {
|
|
7471
|
+
if (!body || !body?.content) {
|
|
7472
|
+
return;
|
|
7473
|
+
}
|
|
7474
|
+
const element = typeof elementOrVisitor === "string" ? elementOrVisitor : void 0;
|
|
7475
|
+
const type = element ? commentBodyElementsTypes[element] : "all";
|
|
7476
|
+
const guard = element ? commentBodyElementsGuards[element] : () => true;
|
|
7477
|
+
const visitor = typeof elementOrVisitor === "function" ? elementOrVisitor : possiblyVisitor;
|
|
7478
|
+
for (const block of body.content) {
|
|
7479
|
+
if (type === "all" || type === "block") {
|
|
7480
|
+
if (guard(block)) {
|
|
7481
|
+
visitor?.(block);
|
|
6306
7482
|
}
|
|
6307
7483
|
}
|
|
6308
|
-
if (
|
|
6309
|
-
|
|
6310
|
-
|
|
6311
|
-
|
|
6312
|
-
|
|
6313
|
-
throw new Error("Please specify a listener callback");
|
|
7484
|
+
if (type === "all" || type === "inline") {
|
|
7485
|
+
for (const inline of block.children) {
|
|
7486
|
+
if (guard(inline)) {
|
|
7487
|
+
visitor?.(inline);
|
|
7488
|
+
}
|
|
6314
7489
|
}
|
|
6315
7490
|
}
|
|
6316
|
-
|
|
6317
|
-
|
|
6318
|
-
|
|
6319
|
-
|
|
6320
|
-
|
|
6321
|
-
|
|
6322
|
-
|
|
6323
|
-
|
|
6324
|
-
|
|
7491
|
+
}
|
|
7492
|
+
}
|
|
7493
|
+
function getMentionedIdsFromCommentBody(body) {
|
|
7494
|
+
const mentionedIds = /* @__PURE__ */ new Set();
|
|
7495
|
+
traverseCommentBody(
|
|
7496
|
+
body,
|
|
7497
|
+
"mention",
|
|
7498
|
+
(mention) => mentionedIds.add(mention.id)
|
|
7499
|
+
);
|
|
7500
|
+
return Array.from(mentionedIds);
|
|
7501
|
+
}
|
|
7502
|
+
async function resolveUsersInCommentBody(body, resolveUsers) {
|
|
7503
|
+
const resolvedUsers = /* @__PURE__ */ new Map();
|
|
7504
|
+
if (!resolveUsers) {
|
|
7505
|
+
return resolvedUsers;
|
|
7506
|
+
}
|
|
7507
|
+
const userIds = getMentionedIdsFromCommentBody(body);
|
|
7508
|
+
const users = await resolveUsers({
|
|
7509
|
+
userIds
|
|
7510
|
+
});
|
|
7511
|
+
for (const [index, userId] of userIds.entries()) {
|
|
7512
|
+
const user = users?.[index];
|
|
7513
|
+
if (user) {
|
|
7514
|
+
resolvedUsers.set(userId, user);
|
|
6325
7515
|
}
|
|
6326
|
-
throw new Error(
|
|
6327
|
-
`${String(first)} is not a value that can be subscribed to.`
|
|
6328
|
-
);
|
|
6329
7516
|
}
|
|
6330
|
-
return
|
|
7517
|
+
return resolvedUsers;
|
|
6331
7518
|
}
|
|
6332
|
-
|
|
6333
|
-
|
|
7519
|
+
var htmlEscapables = {
|
|
7520
|
+
"&": "&",
|
|
7521
|
+
"<": "<",
|
|
7522
|
+
">": ">",
|
|
7523
|
+
'"': """,
|
|
7524
|
+
"'": "'"
|
|
7525
|
+
};
|
|
7526
|
+
var htmlEscapablesRegex = new RegExp(
|
|
7527
|
+
Object.keys(htmlEscapables).map((entity) => `\\${entity}`).join("|"),
|
|
7528
|
+
"g"
|
|
7529
|
+
);
|
|
7530
|
+
function htmlSafe(value) {
|
|
7531
|
+
return new HtmlSafeString([String(value)], []);
|
|
6334
7532
|
}
|
|
6335
|
-
function
|
|
6336
|
-
|
|
6337
|
-
return
|
|
6338
|
-
}
|
|
7533
|
+
function joinHtml(strings) {
|
|
7534
|
+
if (strings.length <= 0) {
|
|
7535
|
+
return new HtmlSafeString([""], []);
|
|
7536
|
+
}
|
|
7537
|
+
return new HtmlSafeString(
|
|
7538
|
+
["", ...Array(strings.length - 1).fill(""), ""],
|
|
7539
|
+
strings
|
|
7540
|
+
);
|
|
6339
7541
|
}
|
|
6340
|
-
function
|
|
6341
|
-
|
|
6342
|
-
|
|
6343
|
-
|
|
6344
|
-
|
|
6345
|
-
|
|
6346
|
-
|
|
6347
|
-
|
|
6348
|
-
|
|
6349
|
-
|
|
6350
|
-
|
|
6351
|
-
url.searchParams.set("roomId", roomId);
|
|
6352
|
-
if (authValue.type === "secret") {
|
|
6353
|
-
url.searchParams.set("tok", authValue.token.raw);
|
|
6354
|
-
} else if (authValue.type === "public") {
|
|
6355
|
-
url.searchParams.set("pubkey", authValue.publicApiKey);
|
|
6356
|
-
} else {
|
|
6357
|
-
return assertNever(authValue, "Unhandled case");
|
|
6358
|
-
}
|
|
6359
|
-
url.searchParams.set("version", PKG_VERSION || "dev");
|
|
6360
|
-
return new ws(url.toString());
|
|
6361
|
-
};
|
|
7542
|
+
function escapeHtml(value) {
|
|
7543
|
+
if (value instanceof HtmlSafeString) {
|
|
7544
|
+
return value.toString();
|
|
7545
|
+
}
|
|
7546
|
+
if (Array.isArray(value)) {
|
|
7547
|
+
return joinHtml(value).toString();
|
|
7548
|
+
}
|
|
7549
|
+
return String(value).replace(
|
|
7550
|
+
htmlEscapablesRegex,
|
|
7551
|
+
(character) => htmlEscapables[character]
|
|
7552
|
+
);
|
|
6362
7553
|
}
|
|
6363
|
-
|
|
6364
|
-
|
|
6365
|
-
|
|
6366
|
-
|
|
6367
|
-
var DEFAULT_THROTTLE = 100;
|
|
6368
|
-
var MIN_BACKGROUND_KEEP_ALIVE_TIMEOUT = 15e3;
|
|
6369
|
-
var MIN_LOST_CONNECTION_TIMEOUT = 200;
|
|
6370
|
-
var RECOMMENDED_MIN_LOST_CONNECTION_TIMEOUT = 1e3;
|
|
6371
|
-
var MAX_LOST_CONNECTION_TIMEOUT = 3e4;
|
|
6372
|
-
var DEFAULT_LOST_CONNECTION_TIMEOUT = 5e3;
|
|
6373
|
-
function getBaseUrlFromClientOptions(clientOptions) {
|
|
6374
|
-
if ("liveblocksServer" in clientOptions) {
|
|
6375
|
-
throw new Error("Client option no longer supported");
|
|
7554
|
+
var HtmlSafeString = class {
|
|
7555
|
+
constructor(strings, values) {
|
|
7556
|
+
this._strings = strings;
|
|
7557
|
+
this._values = values;
|
|
6376
7558
|
}
|
|
6377
|
-
|
|
6378
|
-
return
|
|
6379
|
-
|
|
6380
|
-
|
|
7559
|
+
toString() {
|
|
7560
|
+
return this._strings.reduce((result, str, i) => {
|
|
7561
|
+
return result + escapeHtml(nn(this._values[i - 1])) + str;
|
|
7562
|
+
});
|
|
6381
7563
|
}
|
|
7564
|
+
};
|
|
7565
|
+
function html(strings, ...values) {
|
|
7566
|
+
return new HtmlSafeString(strings, values);
|
|
6382
7567
|
}
|
|
6383
|
-
|
|
6384
|
-
|
|
6385
|
-
|
|
6386
|
-
|
|
6387
|
-
|
|
7568
|
+
var markdownEscapables = {
|
|
7569
|
+
_: "\\_",
|
|
7570
|
+
"*": "\\*",
|
|
7571
|
+
"#": "\\#",
|
|
7572
|
+
"`": "\\`",
|
|
7573
|
+
"~": "\\~",
|
|
7574
|
+
"!": "\\!",
|
|
7575
|
+
"|": "\\|",
|
|
7576
|
+
"(": "\\(",
|
|
7577
|
+
")": "\\)",
|
|
7578
|
+
"{": "\\{",
|
|
7579
|
+
"}": "\\}",
|
|
7580
|
+
"[": "\\[",
|
|
7581
|
+
"]": "\\]"
|
|
7582
|
+
};
|
|
7583
|
+
var markdownEscapablesRegex = new RegExp(
|
|
7584
|
+
Object.keys(markdownEscapables).map((entity) => `\\${entity}`).join("|"),
|
|
7585
|
+
"g"
|
|
7586
|
+
);
|
|
7587
|
+
function joinMarkdown(strings) {
|
|
7588
|
+
if (strings.length <= 0) {
|
|
7589
|
+
return new MarkdownSafeString([""], []);
|
|
7590
|
+
}
|
|
7591
|
+
return new MarkdownSafeString(
|
|
7592
|
+
["", ...Array(strings.length - 1).fill(""), ""],
|
|
7593
|
+
strings
|
|
6388
7594
|
);
|
|
6389
|
-
|
|
6390
|
-
|
|
7595
|
+
}
|
|
7596
|
+
function escapeMarkdown(value) {
|
|
7597
|
+
if (value instanceof MarkdownSafeString) {
|
|
7598
|
+
return value.toString();
|
|
7599
|
+
}
|
|
7600
|
+
if (Array.isArray(value)) {
|
|
7601
|
+
return joinMarkdown(value).toString();
|
|
7602
|
+
}
|
|
7603
|
+
return String(value).replace(
|
|
7604
|
+
markdownEscapablesRegex,
|
|
7605
|
+
(character) => markdownEscapables[character]
|
|
6391
7606
|
);
|
|
6392
|
-
|
|
6393
|
-
|
|
6394
|
-
|
|
6395
|
-
|
|
6396
|
-
|
|
6397
|
-
room.destroy();
|
|
7607
|
+
}
|
|
7608
|
+
var MarkdownSafeString = class {
|
|
7609
|
+
constructor(strings, values) {
|
|
7610
|
+
this._strings = strings;
|
|
7611
|
+
this._values = values;
|
|
6398
7612
|
}
|
|
6399
|
-
|
|
6400
|
-
|
|
6401
|
-
|
|
6402
|
-
|
|
6403
|
-
warn(
|
|
6404
|
-
"This leave function was already called. Calling it more than once has no effect."
|
|
6405
|
-
);
|
|
6406
|
-
} else {
|
|
6407
|
-
if (info.unsubs.size === 0) {
|
|
6408
|
-
teardownRoom(info.room);
|
|
6409
|
-
}
|
|
6410
|
-
}
|
|
6411
|
-
};
|
|
6412
|
-
info.unsubs.add(leave);
|
|
6413
|
-
return {
|
|
6414
|
-
room: info.room,
|
|
6415
|
-
leave
|
|
6416
|
-
};
|
|
7613
|
+
toString() {
|
|
7614
|
+
return this._strings.reduce((result, str, i) => {
|
|
7615
|
+
return result + escapeMarkdown(nn(this._values[i - 1])) + str;
|
|
7616
|
+
});
|
|
6417
7617
|
}
|
|
6418
|
-
|
|
6419
|
-
|
|
6420
|
-
|
|
6421
|
-
|
|
6422
|
-
|
|
6423
|
-
|
|
6424
|
-
|
|
6425
|
-
|
|
6426
|
-
|
|
6427
|
-
const baseUrl = getBaseUrlFromClientOptions(clientOptions);
|
|
6428
|
-
const newRoom = createRoom(
|
|
6429
|
-
{
|
|
6430
|
-
initialPresence: options2.initialPresence ?? {},
|
|
6431
|
-
initialStorage: options2.initialStorage
|
|
6432
|
-
},
|
|
6433
|
-
{
|
|
6434
|
-
roomId,
|
|
6435
|
-
throttleDelay,
|
|
6436
|
-
lostConnectionTimeout,
|
|
6437
|
-
backgroundKeepAliveTimeout,
|
|
6438
|
-
polyfills: clientOptions.polyfills,
|
|
6439
|
-
delegates: clientOptions.mockedDelegates ?? {
|
|
6440
|
-
createSocket: makeCreateSocketDelegateForRoom(
|
|
6441
|
-
roomId,
|
|
6442
|
-
baseUrl,
|
|
6443
|
-
clientOptions.polyfills?.WebSocket
|
|
6444
|
-
),
|
|
6445
|
-
authenticate: makeAuthDelegateForRoom(roomId, authManager)
|
|
6446
|
-
},
|
|
6447
|
-
enableDebugLogging: clientOptions.enableDebugLogging,
|
|
6448
|
-
unstable_batchedUpdates: options2?.unstable_batchedUpdates,
|
|
6449
|
-
baseUrl,
|
|
6450
|
-
unstable_fallbackToHTTP: !!clientOptions.unstable_fallbackToHTTP
|
|
6451
|
-
}
|
|
6452
|
-
);
|
|
6453
|
-
const newRoomInfo = {
|
|
6454
|
-
room: newRoom,
|
|
6455
|
-
unsubs: /* @__PURE__ */ new Set()
|
|
6456
|
-
};
|
|
6457
|
-
roomsById.set(roomId, newRoomInfo);
|
|
6458
|
-
setupDevTools(() => Array.from(roomsById.keys()));
|
|
6459
|
-
linkDevTools(roomId, newRoom);
|
|
6460
|
-
const shouldConnect = options2.autoConnect ?? options2.shouldInitiallyConnect ?? true;
|
|
6461
|
-
if (shouldConnect) {
|
|
6462
|
-
if (typeof atob === "undefined") {
|
|
6463
|
-
if (clientOptions.polyfills?.atob === void 0) {
|
|
6464
|
-
throw new Error(
|
|
6465
|
-
"You need to polyfill atob to use the client in your environment. Please follow the instructions at https://liveblocks.io/docs/errors/liveblocks-client/atob-polyfill"
|
|
6466
|
-
);
|
|
6467
|
-
}
|
|
6468
|
-
global.atob = clientOptions.polyfills.atob;
|
|
6469
|
-
}
|
|
6470
|
-
newRoom.connect();
|
|
6471
|
-
}
|
|
6472
|
-
return leaseRoom(newRoomInfo);
|
|
7618
|
+
};
|
|
7619
|
+
function markdown(strings, ...values) {
|
|
7620
|
+
return new MarkdownSafeString(strings, values);
|
|
7621
|
+
}
|
|
7622
|
+
function toAbsoluteUrl(url) {
|
|
7623
|
+
if (url.startsWith("http://") || url.startsWith("https://")) {
|
|
7624
|
+
return url;
|
|
7625
|
+
} else if (url.startsWith("www.")) {
|
|
7626
|
+
return "https://" + url;
|
|
6473
7627
|
}
|
|
6474
|
-
|
|
6475
|
-
|
|
6476
|
-
|
|
7628
|
+
return;
|
|
7629
|
+
}
|
|
7630
|
+
var stringifyCommentBodyPlainElements = {
|
|
7631
|
+
paragraph: ({ children }) => children,
|
|
7632
|
+
text: ({ element }) => element.text,
|
|
7633
|
+
link: ({ element }) => element.url,
|
|
7634
|
+
mention: ({ element, user }) => {
|
|
7635
|
+
return `@${user?.name ?? element.id}`;
|
|
6477
7636
|
}
|
|
6478
|
-
|
|
6479
|
-
|
|
6480
|
-
|
|
7637
|
+
};
|
|
7638
|
+
var stringifyCommentBodyHtmlElements = {
|
|
7639
|
+
paragraph: ({ children }) => {
|
|
7640
|
+
return children ? html`<p>${htmlSafe(children)}</p>` : children;
|
|
7641
|
+
},
|
|
7642
|
+
text: ({ element }) => {
|
|
7643
|
+
let children = element.text;
|
|
7644
|
+
if (!children) {
|
|
7645
|
+
return children;
|
|
7646
|
+
}
|
|
7647
|
+
if (element.bold) {
|
|
7648
|
+
children = html`<strong>${children}</strong>`;
|
|
7649
|
+
}
|
|
7650
|
+
if (element.italic) {
|
|
7651
|
+
children = html`<em>${children}</em>`;
|
|
7652
|
+
}
|
|
7653
|
+
if (element.strikethrough) {
|
|
7654
|
+
children = html`<s>${children}</s>`;
|
|
7655
|
+
}
|
|
7656
|
+
if (element.code) {
|
|
7657
|
+
children = html`<code>${children}</code>`;
|
|
7658
|
+
}
|
|
7659
|
+
return children;
|
|
7660
|
+
},
|
|
7661
|
+
link: ({ element, href }) => {
|
|
7662
|
+
return html`<a href="${href}" target="_blank" rel="noopener noreferrer">${element.url}</a>`;
|
|
7663
|
+
},
|
|
7664
|
+
mention: ({ element, user }) => {
|
|
7665
|
+
return html`<span data-mention>@${user?.name ?? element.id}</span>`;
|
|
6481
7666
|
}
|
|
6482
|
-
|
|
6483
|
-
|
|
6484
|
-
|
|
6485
|
-
|
|
7667
|
+
};
|
|
7668
|
+
var stringifyCommentBodyMarkdownElements = {
|
|
7669
|
+
paragraph: ({ children }) => {
|
|
7670
|
+
return children;
|
|
7671
|
+
},
|
|
7672
|
+
text: ({ element }) => {
|
|
7673
|
+
let children = element.text;
|
|
7674
|
+
if (!children) {
|
|
7675
|
+
return children;
|
|
6486
7676
|
}
|
|
6487
|
-
|
|
6488
|
-
|
|
6489
|
-
|
|
6490
|
-
|
|
6491
|
-
|
|
6492
|
-
|
|
6493
|
-
|
|
7677
|
+
if (element.bold) {
|
|
7678
|
+
children = markdown`**${children}**`;
|
|
7679
|
+
}
|
|
7680
|
+
if (element.italic) {
|
|
7681
|
+
children = markdown`_${children}_`;
|
|
7682
|
+
}
|
|
7683
|
+
if (element.strikethrough) {
|
|
7684
|
+
children = markdown`~~${children}~~`;
|
|
7685
|
+
}
|
|
7686
|
+
if (element.code) {
|
|
7687
|
+
children = markdown`\`${children}\``;
|
|
6494
7688
|
}
|
|
7689
|
+
return children;
|
|
7690
|
+
},
|
|
7691
|
+
link: ({ element, href }) => {
|
|
7692
|
+
return markdown`[${element.url}](${href})`;
|
|
7693
|
+
},
|
|
7694
|
+
mention: ({ element, user }) => {
|
|
7695
|
+
return markdown`@${user?.name ?? element.id}`;
|
|
6495
7696
|
}
|
|
6496
|
-
|
|
6497
|
-
|
|
6498
|
-
|
|
6499
|
-
|
|
6500
|
-
|
|
6501
|
-
|
|
6502
|
-
|
|
6503
|
-
enterRoom
|
|
7697
|
+
};
|
|
7698
|
+
async function stringifyCommentBody(body, options) {
|
|
7699
|
+
const format = options?.format ?? "plain";
|
|
7700
|
+
const separator = options?.separator ?? (format === "markdown" ? "\n\n" : "\n");
|
|
7701
|
+
const elements = {
|
|
7702
|
+
...format === "html" ? stringifyCommentBodyHtmlElements : format === "markdown" ? stringifyCommentBodyMarkdownElements : stringifyCommentBodyPlainElements,
|
|
7703
|
+
...options?.elements
|
|
6504
7704
|
};
|
|
6505
|
-
|
|
6506
|
-
|
|
6507
|
-
|
|
6508
|
-
throw new Error(
|
|
6509
|
-
max !== void 0 ? `${option} should be between ${recommendedMin ?? min} and ${max}.` : `${option} should be at least ${recommendedMin ?? min}.`
|
|
6510
|
-
);
|
|
6511
|
-
}
|
|
6512
|
-
return value;
|
|
6513
|
-
}
|
|
6514
|
-
function getBackgroundKeepAliveTimeout(value) {
|
|
6515
|
-
if (value === void 0)
|
|
6516
|
-
return void 0;
|
|
6517
|
-
return checkBounds(
|
|
6518
|
-
"backgroundKeepAliveTimeout",
|
|
6519
|
-
value,
|
|
6520
|
-
MIN_BACKGROUND_KEEP_ALIVE_TIMEOUT
|
|
6521
|
-
);
|
|
6522
|
-
}
|
|
6523
|
-
function getThrottle(value) {
|
|
6524
|
-
return checkBounds("throttle", value, MIN_THROTTLE, MAX_THROTTLE);
|
|
6525
|
-
}
|
|
6526
|
-
function getLostConnectionTimeout(value) {
|
|
6527
|
-
return checkBounds(
|
|
6528
|
-
"lostConnectionTimeout",
|
|
6529
|
-
value,
|
|
6530
|
-
MIN_LOST_CONNECTION_TIMEOUT,
|
|
6531
|
-
MAX_LOST_CONNECTION_TIMEOUT,
|
|
6532
|
-
RECOMMENDED_MIN_LOST_CONNECTION_TIMEOUT
|
|
7705
|
+
const resolvedUsers = await resolveUsersInCommentBody(
|
|
7706
|
+
body,
|
|
7707
|
+
options?.resolveUsers
|
|
6533
7708
|
);
|
|
7709
|
+
const blocks = body.content.flatMap((block, blockIndex) => {
|
|
7710
|
+
switch (block.type) {
|
|
7711
|
+
case "paragraph": {
|
|
7712
|
+
const inlines = block.children.flatMap((inline, inlineIndex) => {
|
|
7713
|
+
if (isCommentBodyMention(inline)) {
|
|
7714
|
+
return inline.id ? [
|
|
7715
|
+
elements.mention(
|
|
7716
|
+
{
|
|
7717
|
+
element: inline,
|
|
7718
|
+
user: resolvedUsers.get(inline.id)
|
|
7719
|
+
},
|
|
7720
|
+
inlineIndex
|
|
7721
|
+
)
|
|
7722
|
+
] : [];
|
|
7723
|
+
}
|
|
7724
|
+
if (isCommentBodyLink(inline)) {
|
|
7725
|
+
return [
|
|
7726
|
+
elements.link(
|
|
7727
|
+
{
|
|
7728
|
+
element: inline,
|
|
7729
|
+
href: toAbsoluteUrl(inline.url) ?? inline.url
|
|
7730
|
+
},
|
|
7731
|
+
inlineIndex
|
|
7732
|
+
)
|
|
7733
|
+
];
|
|
7734
|
+
}
|
|
7735
|
+
if (isCommentBodyText(inline)) {
|
|
7736
|
+
return [elements.text({ element: inline }, inlineIndex)];
|
|
7737
|
+
}
|
|
7738
|
+
return [];
|
|
7739
|
+
});
|
|
7740
|
+
return [
|
|
7741
|
+
elements.paragraph(
|
|
7742
|
+
{ element: block, children: inlines.join("") },
|
|
7743
|
+
blockIndex
|
|
7744
|
+
)
|
|
7745
|
+
];
|
|
7746
|
+
}
|
|
7747
|
+
default:
|
|
7748
|
+
return [];
|
|
7749
|
+
}
|
|
7750
|
+
});
|
|
7751
|
+
return blocks.join(separator);
|
|
6534
7752
|
}
|
|
6535
7753
|
|
|
6536
7754
|
// src/crdts/utils.ts
|
|
@@ -6864,161 +8082,6 @@ function legacy_patchImmutableNode(state, path, update) {
|
|
|
6864
8082
|
}
|
|
6865
8083
|
}
|
|
6866
8084
|
|
|
6867
|
-
// src/lib/shallow.ts
|
|
6868
|
-
function shallowArray(xs, ys) {
|
|
6869
|
-
if (xs.length !== ys.length) {
|
|
6870
|
-
return false;
|
|
6871
|
-
}
|
|
6872
|
-
for (let i = 0; i < xs.length; i++) {
|
|
6873
|
-
if (!Object.is(xs[i], ys[i])) {
|
|
6874
|
-
return false;
|
|
6875
|
-
}
|
|
6876
|
-
}
|
|
6877
|
-
return true;
|
|
6878
|
-
}
|
|
6879
|
-
function shallowObj(objA, objB) {
|
|
6880
|
-
if (typeof objA !== "object" || objA === null || typeof objB !== "object" || objB === null || Object.prototype.toString.call(objA) !== "[object Object]" || Object.prototype.toString.call(objB) !== "[object Object]") {
|
|
6881
|
-
return false;
|
|
6882
|
-
}
|
|
6883
|
-
const keysA = Object.keys(objA);
|
|
6884
|
-
if (keysA.length !== Object.keys(objB).length) {
|
|
6885
|
-
return false;
|
|
6886
|
-
}
|
|
6887
|
-
return keysA.every(
|
|
6888
|
-
(key) => Object.prototype.hasOwnProperty.call(objB, key) && Object.is(objA[key], objB[key])
|
|
6889
|
-
);
|
|
6890
|
-
}
|
|
6891
|
-
function shallow(a, b) {
|
|
6892
|
-
if (Object.is(a, b)) {
|
|
6893
|
-
return true;
|
|
6894
|
-
}
|
|
6895
|
-
const isArrayA = Array.isArray(a);
|
|
6896
|
-
const isArrayB = Array.isArray(b);
|
|
6897
|
-
if (isArrayA || isArrayB) {
|
|
6898
|
-
if (!isArrayA || !isArrayB) {
|
|
6899
|
-
return false;
|
|
6900
|
-
}
|
|
6901
|
-
return shallowArray(a, b);
|
|
6902
|
-
}
|
|
6903
|
-
return shallowObj(a, b);
|
|
6904
|
-
}
|
|
6905
|
-
|
|
6906
|
-
// src/lib/AsyncCache.ts
|
|
6907
|
-
var noop = () => {
|
|
6908
|
-
};
|
|
6909
|
-
function isShallowEqual(a, b) {
|
|
6910
|
-
if (a.isLoading !== b.isLoading || a.data === void 0 !== (b.data === void 0) || a.error === void 0 !== (b.error === void 0)) {
|
|
6911
|
-
return false;
|
|
6912
|
-
} else {
|
|
6913
|
-
return shallow(a.data, b.data) && shallow(a.error, b.error);
|
|
6914
|
-
}
|
|
6915
|
-
}
|
|
6916
|
-
function createCacheItem(key, asyncFunction, options) {
|
|
6917
|
-
const $asyncFunction = async () => asyncFunction(key);
|
|
6918
|
-
const context = {
|
|
6919
|
-
isInvalid: true
|
|
6920
|
-
};
|
|
6921
|
-
let state = { isLoading: false };
|
|
6922
|
-
let previousState = { isLoading: false };
|
|
6923
|
-
const eventSource2 = makeEventSource();
|
|
6924
|
-
function notify() {
|
|
6925
|
-
const isEqual = options?.isStateEqual ?? isShallowEqual;
|
|
6926
|
-
if (!isEqual(previousState, state)) {
|
|
6927
|
-
previousState = state;
|
|
6928
|
-
eventSource2.notify(state);
|
|
6929
|
-
}
|
|
6930
|
-
}
|
|
6931
|
-
async function resolve() {
|
|
6932
|
-
if (!context.promise) {
|
|
6933
|
-
return;
|
|
6934
|
-
}
|
|
6935
|
-
try {
|
|
6936
|
-
const data = await context.promise;
|
|
6937
|
-
context.isInvalid = false;
|
|
6938
|
-
state = {
|
|
6939
|
-
isLoading: false,
|
|
6940
|
-
data
|
|
6941
|
-
};
|
|
6942
|
-
} catch (error3) {
|
|
6943
|
-
state = {
|
|
6944
|
-
isLoading: false,
|
|
6945
|
-
data: state.data,
|
|
6946
|
-
error: error3
|
|
6947
|
-
};
|
|
6948
|
-
}
|
|
6949
|
-
context.promise = void 0;
|
|
6950
|
-
notify();
|
|
6951
|
-
}
|
|
6952
|
-
async function revalidate() {
|
|
6953
|
-
context.isInvalid = true;
|
|
6954
|
-
return get();
|
|
6955
|
-
}
|
|
6956
|
-
async function get() {
|
|
6957
|
-
if (context.isInvalid) {
|
|
6958
|
-
if (!context.promise) {
|
|
6959
|
-
context.isInvalid = true;
|
|
6960
|
-
context.promise = $asyncFunction();
|
|
6961
|
-
state = { isLoading: true, data: state.data };
|
|
6962
|
-
notify();
|
|
6963
|
-
}
|
|
6964
|
-
await resolve();
|
|
6965
|
-
}
|
|
6966
|
-
return getState();
|
|
6967
|
-
}
|
|
6968
|
-
function getState() {
|
|
6969
|
-
return state;
|
|
6970
|
-
}
|
|
6971
|
-
return {
|
|
6972
|
-
...eventSource2.observable,
|
|
6973
|
-
get,
|
|
6974
|
-
getState,
|
|
6975
|
-
revalidate
|
|
6976
|
-
};
|
|
6977
|
-
}
|
|
6978
|
-
function createAsyncCache(asyncFunction, options) {
|
|
6979
|
-
const cache = /* @__PURE__ */ new Map();
|
|
6980
|
-
function create(key) {
|
|
6981
|
-
let cacheItem = cache.get(key);
|
|
6982
|
-
if (cacheItem) {
|
|
6983
|
-
return cacheItem;
|
|
6984
|
-
}
|
|
6985
|
-
cacheItem = createCacheItem(key, asyncFunction, options);
|
|
6986
|
-
cache.set(key, cacheItem);
|
|
6987
|
-
return cacheItem;
|
|
6988
|
-
}
|
|
6989
|
-
function get(key) {
|
|
6990
|
-
return create(key).get();
|
|
6991
|
-
}
|
|
6992
|
-
function getState(key) {
|
|
6993
|
-
return cache.get(key)?.getState();
|
|
6994
|
-
}
|
|
6995
|
-
function revalidate(key) {
|
|
6996
|
-
return create(key).revalidate();
|
|
6997
|
-
}
|
|
6998
|
-
function subscribe(key, callback) {
|
|
6999
|
-
return create(key).subscribe(callback) ?? noop;
|
|
7000
|
-
}
|
|
7001
|
-
function subscribeOnce(key, callback) {
|
|
7002
|
-
return create(key).subscribeOnce(callback) ?? noop;
|
|
7003
|
-
}
|
|
7004
|
-
function has(key) {
|
|
7005
|
-
return cache.has(key);
|
|
7006
|
-
}
|
|
7007
|
-
function clear() {
|
|
7008
|
-
cache.clear();
|
|
7009
|
-
}
|
|
7010
|
-
return {
|
|
7011
|
-
create,
|
|
7012
|
-
get,
|
|
7013
|
-
getState,
|
|
7014
|
-
revalidate,
|
|
7015
|
-
subscribe,
|
|
7016
|
-
subscribeOnce,
|
|
7017
|
-
has,
|
|
7018
|
-
clear
|
|
7019
|
-
};
|
|
7020
|
-
}
|
|
7021
|
-
|
|
7022
8085
|
// src/lib/Poller.ts
|
|
7023
8086
|
function makePoller(callback) {
|
|
7024
8087
|
let context = {
|
|
@@ -7108,19 +8171,43 @@ function makePoller(callback) {
|
|
|
7108
8171
|
};
|
|
7109
8172
|
}
|
|
7110
8173
|
|
|
7111
|
-
// src/lib/
|
|
7112
|
-
function
|
|
7113
|
-
if (
|
|
7114
|
-
return
|
|
8174
|
+
// src/lib/shallow.ts
|
|
8175
|
+
function shallowArray(xs, ys) {
|
|
8176
|
+
if (xs.length !== ys.length) {
|
|
8177
|
+
return false;
|
|
7115
8178
|
}
|
|
7116
|
-
|
|
7117
|
-
(
|
|
7118
|
-
|
|
7119
|
-
|
|
7120
|
-
|
|
7121
|
-
|
|
8179
|
+
for (let i = 0; i < xs.length; i++) {
|
|
8180
|
+
if (!Object.is(xs[i], ys[i])) {
|
|
8181
|
+
return false;
|
|
8182
|
+
}
|
|
8183
|
+
}
|
|
8184
|
+
return true;
|
|
8185
|
+
}
|
|
8186
|
+
function shallowObj(objA, objB) {
|
|
8187
|
+
if (typeof objA !== "object" || objA === null || typeof objB !== "object" || objB === null || Object.prototype.toString.call(objA) !== "[object Object]" || Object.prototype.toString.call(objB) !== "[object Object]") {
|
|
8188
|
+
return false;
|
|
8189
|
+
}
|
|
8190
|
+
const keysA = Object.keys(objA);
|
|
8191
|
+
if (keysA.length !== Object.keys(objB).length) {
|
|
8192
|
+
return false;
|
|
8193
|
+
}
|
|
8194
|
+
return keysA.every(
|
|
8195
|
+
(key) => Object.prototype.hasOwnProperty.call(objB, key) && Object.is(objA[key], objB[key])
|
|
7122
8196
|
);
|
|
7123
|
-
|
|
8197
|
+
}
|
|
8198
|
+
function shallow(a, b) {
|
|
8199
|
+
if (Object.is(a, b)) {
|
|
8200
|
+
return true;
|
|
8201
|
+
}
|
|
8202
|
+
const isArrayA = Array.isArray(a);
|
|
8203
|
+
const isArrayB = Array.isArray(b);
|
|
8204
|
+
if (isArrayA || isArrayB) {
|
|
8205
|
+
if (!isArrayA || !isArrayB) {
|
|
8206
|
+
return false;
|
|
8207
|
+
}
|
|
8208
|
+
return shallowArray(a, b);
|
|
8209
|
+
}
|
|
8210
|
+
return shallowObj(a, b);
|
|
7124
8211
|
}
|
|
7125
8212
|
|
|
7126
8213
|
// src/index.ts
|
|
@@ -7132,9 +8219,13 @@ export {
|
|
|
7132
8219
|
LiveList,
|
|
7133
8220
|
LiveMap,
|
|
7134
8221
|
LiveObject,
|
|
8222
|
+
NotificationsApiError,
|
|
7135
8223
|
OpCode,
|
|
7136
8224
|
ServerMsgCode,
|
|
7137
8225
|
WebsocketCloseCodes,
|
|
8226
|
+
ackOp,
|
|
8227
|
+
addReaction,
|
|
8228
|
+
applyOptimisticUpdates,
|
|
7138
8229
|
asPos,
|
|
7139
8230
|
assert,
|
|
7140
8231
|
assertNever,
|
|
@@ -7143,10 +8234,10 @@ export {
|
|
|
7143
8234
|
fancy_console_exports as console,
|
|
7144
8235
|
convertToCommentData,
|
|
7145
8236
|
convertToCommentUserReaction,
|
|
8237
|
+
convertToInboxNotificationData,
|
|
7146
8238
|
convertToThreadData,
|
|
7147
|
-
createAsyncCache,
|
|
7148
8239
|
createClient,
|
|
7149
|
-
|
|
8240
|
+
deleteComment,
|
|
7150
8241
|
deprecate,
|
|
7151
8242
|
deprecateIf,
|
|
7152
8243
|
detectDupes,
|
|
@@ -7160,20 +8251,24 @@ export {
|
|
|
7160
8251
|
isLiveNode,
|
|
7161
8252
|
isPlainObject,
|
|
7162
8253
|
isRootCrdt,
|
|
8254
|
+
kInternal,
|
|
7163
8255
|
legacy_patchImmutableObject,
|
|
7164
8256
|
lsonToJson,
|
|
7165
8257
|
makeEventSource,
|
|
7166
8258
|
makePoller,
|
|
7167
8259
|
makePosition,
|
|
7168
8260
|
nn,
|
|
8261
|
+
objectToQuery,
|
|
7169
8262
|
patchLiveObjectKey,
|
|
7170
8263
|
raise,
|
|
8264
|
+
removeReaction,
|
|
7171
8265
|
shallow,
|
|
7172
8266
|
stringify,
|
|
7173
8267
|
stringifyCommentBody,
|
|
7174
8268
|
throwUsageError,
|
|
7175
8269
|
toPlainLson,
|
|
7176
8270
|
tryParseJson,
|
|
8271
|
+
upsertComment,
|
|
7177
8272
|
withTimeout
|
|
7178
8273
|
};
|
|
7179
8274
|
//# sourceMappingURL=index.mjs.map
|