@liveblocks/core 2.17.0-channels1 → 2.17.0-rc1
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 +98 -113
- package/dist/index.d.ts +98 -113
- package/dist/index.js +373 -246
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +267 -140
- package/dist/index.mjs.map +1 -1
- package/package.json +2 -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 = "2.17.0-
|
|
9
|
+
var PKG_VERSION = "2.17.0-rc1";
|
|
10
10
|
var PKG_FORMAT = "esm";
|
|
11
11
|
|
|
12
12
|
// src/dupe-detection.ts
|
|
@@ -166,6 +166,14 @@ function wrapWithTitle(method) {
|
|
|
166
166
|
var warnWithTitle = wrapWithTitle("warn");
|
|
167
167
|
var errorWithTitle = wrapWithTitle("error");
|
|
168
168
|
|
|
169
|
+
// src/lib/guards.ts
|
|
170
|
+
function isPlainObject(blob) {
|
|
171
|
+
return blob !== null && typeof blob === "object" && Object.prototype.toString.call(blob) === "[object Object]";
|
|
172
|
+
}
|
|
173
|
+
function isStartsWithOperator(blob) {
|
|
174
|
+
return isPlainObject(blob) && typeof blob.startsWith === "string";
|
|
175
|
+
}
|
|
176
|
+
|
|
169
177
|
// src/lib/utils.ts
|
|
170
178
|
function raise(msg) {
|
|
171
179
|
throw new Error(msg);
|
|
@@ -173,12 +181,6 @@ function raise(msg) {
|
|
|
173
181
|
function entries(obj) {
|
|
174
182
|
return Object.entries(obj);
|
|
175
183
|
}
|
|
176
|
-
function keys(obj) {
|
|
177
|
-
return Object.keys(obj);
|
|
178
|
-
}
|
|
179
|
-
function values(obj) {
|
|
180
|
-
return Object.values(obj);
|
|
181
|
-
}
|
|
182
184
|
function mapValues(obj, mapFn) {
|
|
183
185
|
const result = {};
|
|
184
186
|
for (const pair of Object.entries(obj)) {
|
|
@@ -257,13 +259,48 @@ function memoizeOnSuccess(factoryFn) {
|
|
|
257
259
|
}
|
|
258
260
|
|
|
259
261
|
// src/lib/autoRetry.ts
|
|
260
|
-
var HttpError = class extends Error {
|
|
261
|
-
|
|
262
|
+
var HttpError = class _HttpError extends Error {
|
|
263
|
+
response;
|
|
264
|
+
details;
|
|
265
|
+
constructor(message, response, details) {
|
|
262
266
|
super(message);
|
|
263
|
-
this.
|
|
264
|
-
this.
|
|
267
|
+
this.name = "HttpError";
|
|
268
|
+
this.response = response;
|
|
265
269
|
this.details = details;
|
|
266
270
|
}
|
|
271
|
+
static async fromResponse(response) {
|
|
272
|
+
let bodyAsText;
|
|
273
|
+
try {
|
|
274
|
+
bodyAsText = await response.text();
|
|
275
|
+
} catch {
|
|
276
|
+
}
|
|
277
|
+
const bodyAsJson = bodyAsText ? tryParseJson(bodyAsText) : void 0;
|
|
278
|
+
let bodyAsJsonObject;
|
|
279
|
+
if (isPlainObject(bodyAsJson)) {
|
|
280
|
+
bodyAsJsonObject = bodyAsJson;
|
|
281
|
+
}
|
|
282
|
+
let message = "";
|
|
283
|
+
message ||= typeof bodyAsJsonObject?.message === "string" ? bodyAsJsonObject.message : "";
|
|
284
|
+
message ||= typeof bodyAsJsonObject?.error === "string" ? bodyAsJsonObject.error : "";
|
|
285
|
+
if (bodyAsJson === void 0) {
|
|
286
|
+
message ||= bodyAsText || "";
|
|
287
|
+
}
|
|
288
|
+
message ||= response.statusText;
|
|
289
|
+
let path;
|
|
290
|
+
try {
|
|
291
|
+
path = new URL(response.url).pathname;
|
|
292
|
+
} catch {
|
|
293
|
+
}
|
|
294
|
+
message += path !== void 0 ? ` (got status ${response.status} from ${path})` : ` (got status ${response.status})`;
|
|
295
|
+
const details = bodyAsJsonObject;
|
|
296
|
+
return new _HttpError(message, response, details);
|
|
297
|
+
}
|
|
298
|
+
/**
|
|
299
|
+
* Convenience accessor for response.status.
|
|
300
|
+
*/
|
|
301
|
+
get status() {
|
|
302
|
+
return this.response.status;
|
|
303
|
+
}
|
|
267
304
|
};
|
|
268
305
|
var DONT_RETRY_4XX = (x) => x instanceof HttpError && x.status >= 400 && x.status < 500;
|
|
269
306
|
async function autoRetry(promiseFn, maxTries, backoff, shouldStopRetrying = DONT_RETRY_4XX) {
|
|
@@ -329,7 +366,12 @@ function makeEventSource() {
|
|
|
329
366
|
}).finally(() => unsub?.());
|
|
330
367
|
}
|
|
331
368
|
function notify(event) {
|
|
332
|
-
|
|
369
|
+
let called = false;
|
|
370
|
+
for (const callback of _observers) {
|
|
371
|
+
callback(event);
|
|
372
|
+
called = true;
|
|
373
|
+
}
|
|
374
|
+
return called;
|
|
333
375
|
}
|
|
334
376
|
function count() {
|
|
335
377
|
return _observers.size;
|
|
@@ -370,8 +412,9 @@ function makeBufferableEventSource() {
|
|
|
370
412
|
function notifyOrBuffer(event) {
|
|
371
413
|
if (_buffer !== null) {
|
|
372
414
|
_buffer.push(event);
|
|
415
|
+
return false;
|
|
373
416
|
} else {
|
|
374
|
-
eventSource2.notify(event);
|
|
417
|
+
return eventSource2.notify(event);
|
|
375
418
|
}
|
|
376
419
|
}
|
|
377
420
|
return {
|
|
@@ -676,32 +719,15 @@ var MutableSignal = class extends AbstractSignal {
|
|
|
676
719
|
};
|
|
677
720
|
|
|
678
721
|
// src/lib/stringify.ts
|
|
679
|
-
var EXPLICIT_UNDEFINED_PLACEHOLDER = "_explicit_undefined";
|
|
680
722
|
function replacer(_key, value) {
|
|
681
723
|
return value !== null && typeof value === "object" && !Array.isArray(value) ? Object.keys(value).sort().reduce((sorted, key) => {
|
|
682
724
|
sorted[key] = value[key];
|
|
683
725
|
return sorted;
|
|
684
|
-
}, {}) : value
|
|
685
|
-
}
|
|
686
|
-
function reviver(key, value) {
|
|
687
|
-
if (!key && value === EXPLICIT_UNDEFINED_PLACEHOLDER) {
|
|
688
|
-
return void 0;
|
|
689
|
-
}
|
|
690
|
-
if (value && typeof value === "object") {
|
|
691
|
-
for (const k in value) {
|
|
692
|
-
if (value[k] === EXPLICIT_UNDEFINED_PLACEHOLDER) {
|
|
693
|
-
Object.defineProperty(value, k, { value: void 0 });
|
|
694
|
-
}
|
|
695
|
-
}
|
|
696
|
-
}
|
|
697
|
-
return value;
|
|
726
|
+
}, {}) : value;
|
|
698
727
|
}
|
|
699
728
|
function stringify(value) {
|
|
700
729
|
return JSON.stringify(value, replacer);
|
|
701
730
|
}
|
|
702
|
-
function unstringify(value) {
|
|
703
|
-
return JSON.parse(value, reviver);
|
|
704
|
-
}
|
|
705
731
|
|
|
706
732
|
// src/lib/batch.ts
|
|
707
733
|
var DEFAULT_SIZE = 50;
|
|
@@ -917,14 +943,6 @@ var DefaultMap = class extends Map {
|
|
|
917
943
|
}
|
|
918
944
|
};
|
|
919
945
|
|
|
920
|
-
// src/lib/guards.ts
|
|
921
|
-
function isPlainObject(blob) {
|
|
922
|
-
return blob !== null && typeof blob === "object" && Object.prototype.toString.call(blob) === "[object Object]";
|
|
923
|
-
}
|
|
924
|
-
function isStartsWithOperator(blob) {
|
|
925
|
-
return isPlainObject(blob) && typeof blob.startsWith === "string";
|
|
926
|
-
}
|
|
927
|
-
|
|
928
946
|
// src/lib/objectToQuery.ts
|
|
929
947
|
var identifierRegex = /^[a-zA-Z_][a-zA-Z0-9_]*$/;
|
|
930
948
|
function objectToQuery(obj) {
|
|
@@ -974,9 +992,7 @@ function objectToQuery(obj) {
|
|
|
974
992
|
...getFiltersFromKeyValuePairsWithOperator(nKeyValuePairsWithOperator)
|
|
975
993
|
];
|
|
976
994
|
});
|
|
977
|
-
return filterList.map(
|
|
978
|
-
({ key, operator, value }) => formatFilter(key, operator, formatFilterValue(value))
|
|
979
|
-
).join(" AND ");
|
|
995
|
+
return filterList.map(({ key, operator, value }) => `${key}${operator}${quote(value)}`).join(" ");
|
|
980
996
|
}
|
|
981
997
|
var getFiltersFromKeyValuePairs = (keyValuePairs) => {
|
|
982
998
|
const filters = [];
|
|
@@ -1003,29 +1019,27 @@ var getFiltersFromKeyValuePairsWithOperator = (keyValuePairsWithOperator) => {
|
|
|
1003
1019
|
return filters;
|
|
1004
1020
|
};
|
|
1005
1021
|
var isSimpleValue = (value) => {
|
|
1006
|
-
return typeof value === "string" || typeof value === "number" || typeof value === "boolean";
|
|
1007
|
-
};
|
|
1008
|
-
var formatFilter = (key, operator, value) => {
|
|
1009
|
-
return `${key}${operator}${value}`;
|
|
1022
|
+
return typeof value === "string" || typeof value === "number" || typeof value === "boolean" || value === null;
|
|
1010
1023
|
};
|
|
1011
1024
|
var formatFilterKey = (key, nestedKey) => {
|
|
1012
1025
|
if (nestedKey) {
|
|
1013
|
-
return `${key}[${
|
|
1026
|
+
return `${key}[${quote(nestedKey)}]`;
|
|
1014
1027
|
}
|
|
1015
1028
|
return key;
|
|
1016
1029
|
};
|
|
1017
|
-
var formatFilterValue = (value) => {
|
|
1018
|
-
if (typeof value === "string") {
|
|
1019
|
-
if (isStringEmpty(value)) {
|
|
1020
|
-
throw new Error("Value cannot be empty");
|
|
1021
|
-
}
|
|
1022
|
-
return JSON.stringify(value);
|
|
1023
|
-
}
|
|
1024
|
-
return value.toString();
|
|
1025
|
-
};
|
|
1026
1030
|
var isStringEmpty = (value) => {
|
|
1027
1031
|
return !value || value.toString().trim() === "";
|
|
1028
1032
|
};
|
|
1033
|
+
function quote(input) {
|
|
1034
|
+
const result = JSON.stringify(input);
|
|
1035
|
+
if (typeof input !== "string") {
|
|
1036
|
+
return result;
|
|
1037
|
+
}
|
|
1038
|
+
if (result.includes("'")) {
|
|
1039
|
+
return result;
|
|
1040
|
+
}
|
|
1041
|
+
return `'${result.slice(1, -1).replace(/\\"/g, '"')}'`;
|
|
1042
|
+
}
|
|
1029
1043
|
|
|
1030
1044
|
// src/lib/url.ts
|
|
1031
1045
|
function toURLSearchParams(params) {
|
|
@@ -1044,9 +1058,9 @@ function urljoin(baseUrl, path, params) {
|
|
|
1044
1058
|
}
|
|
1045
1059
|
return url2.toString();
|
|
1046
1060
|
}
|
|
1047
|
-
function url(strings, ...
|
|
1061
|
+
function url(strings, ...values) {
|
|
1048
1062
|
return strings.reduce(
|
|
1049
|
-
(result, str, i) => result + encodeURIComponent(
|
|
1063
|
+
(result, str, i) => result + encodeURIComponent(values[i - 1] ?? "") + str
|
|
1050
1064
|
);
|
|
1051
1065
|
}
|
|
1052
1066
|
|
|
@@ -1691,21 +1705,6 @@ function createApiClient({
|
|
|
1691
1705
|
await authManager.getAuthValue({ requestedScope: "comments:read" })
|
|
1692
1706
|
);
|
|
1693
1707
|
}
|
|
1694
|
-
async function getChannelsNotificationSettings(options) {
|
|
1695
|
-
return httpClient.get(
|
|
1696
|
-
url`/v2/c/channels-notification-settings`,
|
|
1697
|
-
await authManager.getAuthValue({ requestedScope: "comments:read" }),
|
|
1698
|
-
void 0,
|
|
1699
|
-
{ signal: options?.signal }
|
|
1700
|
-
);
|
|
1701
|
-
}
|
|
1702
|
-
async function updateChannelsNotificationSettings(settings) {
|
|
1703
|
-
return httpClient.post(
|
|
1704
|
-
url`/v2/c/channels-notification-settings`,
|
|
1705
|
-
await authManager.getAuthValue({ requestedScope: "comments:read" }),
|
|
1706
|
-
settings
|
|
1707
|
-
);
|
|
1708
|
-
}
|
|
1709
1708
|
async function getUserThreads_experimental(options) {
|
|
1710
1709
|
let query;
|
|
1711
1710
|
if (options?.query) {
|
|
@@ -1771,9 +1770,7 @@ function createApiClient({
|
|
|
1771
1770
|
// Room notifications
|
|
1772
1771
|
markRoomInboxNotificationAsRead,
|
|
1773
1772
|
updateNotificationSettings,
|
|
1774
|
-
// Channel notification settings
|
|
1775
1773
|
getNotificationSettings,
|
|
1776
|
-
updateChannelsNotificationSettings,
|
|
1777
1774
|
// Room text editor
|
|
1778
1775
|
createTextMention,
|
|
1779
1776
|
deleteTextMention,
|
|
@@ -1797,7 +1794,6 @@ function createApiClient({
|
|
|
1797
1794
|
markInboxNotificationAsRead,
|
|
1798
1795
|
deleteAllInboxNotifications,
|
|
1799
1796
|
deleteInboxNotification,
|
|
1800
|
-
getChannelsNotificationSettings,
|
|
1801
1797
|
// User threads
|
|
1802
1798
|
getUserThreads_experimental,
|
|
1803
1799
|
getUserThreadsSince_experimental
|
|
@@ -1868,14 +1864,7 @@ var HttpClient = class {
|
|
|
1868
1864
|
async #fetch(endpoint, authValue, options, params) {
|
|
1869
1865
|
const response = await this.#rawFetch(endpoint, authValue, options, params);
|
|
1870
1866
|
if (!response.ok) {
|
|
1871
|
-
|
|
1872
|
-
try {
|
|
1873
|
-
const errorBody = await response.json();
|
|
1874
|
-
error3 = new HttpError(errorBody.message, response.status, errorBody);
|
|
1875
|
-
} catch {
|
|
1876
|
-
error3 = new HttpError(response.statusText, response.status);
|
|
1877
|
-
}
|
|
1878
|
-
throw error3;
|
|
1867
|
+
throw await HttpError.fromResponse(response);
|
|
1879
1868
|
}
|
|
1880
1869
|
let body;
|
|
1881
1870
|
try {
|
|
@@ -2519,13 +2508,6 @@ var StopRetrying = class extends Error {
|
|
|
2519
2508
|
super(reason);
|
|
2520
2509
|
}
|
|
2521
2510
|
};
|
|
2522
|
-
var LiveblocksError = class extends Error {
|
|
2523
|
-
/** @internal */
|
|
2524
|
-
constructor(message, code) {
|
|
2525
|
-
super(message);
|
|
2526
|
-
this.code = code;
|
|
2527
|
-
}
|
|
2528
|
-
};
|
|
2529
2511
|
function nextBackoffDelay(currentDelay, delays) {
|
|
2530
2512
|
return delays.find((delay) => delay > currentDelay) ?? delays[delays.length - 1];
|
|
2531
2513
|
}
|
|
@@ -2635,11 +2617,10 @@ var assign = (patch) => (ctx) => ctx.patch(patch);
|
|
|
2635
2617
|
function createConnectionStateMachine(delegates, options) {
|
|
2636
2618
|
const onMessage = makeBufferableEventSource();
|
|
2637
2619
|
onMessage.pause();
|
|
2638
|
-
const
|
|
2639
|
-
function fireErrorEvent(
|
|
2620
|
+
const onConnectionError = makeEventSource();
|
|
2621
|
+
function fireErrorEvent(message, code) {
|
|
2640
2622
|
return () => {
|
|
2641
|
-
|
|
2642
|
-
onLiveblocksError.notify(err);
|
|
2623
|
+
onConnectionError.notify({ message, code });
|
|
2643
2624
|
};
|
|
2644
2625
|
}
|
|
2645
2626
|
const initialContext = {
|
|
@@ -2997,7 +2978,7 @@ function createConnectionStateMachine(delegates, options) {
|
|
|
2997
2978
|
didConnect,
|
|
2998
2979
|
didDisconnect,
|
|
2999
2980
|
onMessage: onMessage.observable,
|
|
3000
|
-
|
|
2981
|
+
onConnectionError: onConnectionError.observable
|
|
3001
2982
|
}
|
|
3002
2983
|
};
|
|
3003
2984
|
}
|
|
@@ -6261,8 +6242,85 @@ var ManagedOthers = class {
|
|
|
6261
6242
|
}
|
|
6262
6243
|
};
|
|
6263
6244
|
|
|
6245
|
+
// src/types/LiveblocksError.ts
|
|
6246
|
+
var LiveblocksError = class _LiveblocksError extends Error {
|
|
6247
|
+
context;
|
|
6248
|
+
constructor(message, context, cause) {
|
|
6249
|
+
super(message, { cause });
|
|
6250
|
+
this.context = context;
|
|
6251
|
+
this.name = "LiveblocksError";
|
|
6252
|
+
}
|
|
6253
|
+
/** Convenience accessor for error.context.roomId (if available) */
|
|
6254
|
+
get roomId() {
|
|
6255
|
+
return this.context.roomId;
|
|
6256
|
+
}
|
|
6257
|
+
/** @deprecated Prefer using `context.code` instead, to enable type narrowing */
|
|
6258
|
+
get code() {
|
|
6259
|
+
return this.context.code;
|
|
6260
|
+
}
|
|
6261
|
+
/**
|
|
6262
|
+
* Creates a LiveblocksError from a generic error, by attaching Liveblocks
|
|
6263
|
+
* contextual information like room ID, thread ID, etc.
|
|
6264
|
+
*/
|
|
6265
|
+
static from(context, cause) {
|
|
6266
|
+
return new _LiveblocksError(
|
|
6267
|
+
defaultMessageFromContext(context),
|
|
6268
|
+
context,
|
|
6269
|
+
cause
|
|
6270
|
+
);
|
|
6271
|
+
}
|
|
6272
|
+
};
|
|
6273
|
+
function defaultMessageFromContext(context) {
|
|
6274
|
+
switch (context.type) {
|
|
6275
|
+
case "ROOM_CONNECTION_ERROR": {
|
|
6276
|
+
switch (context.code) {
|
|
6277
|
+
case 4001:
|
|
6278
|
+
return "Not allowed to connect to the room";
|
|
6279
|
+
case 4005:
|
|
6280
|
+
return "Room is already full";
|
|
6281
|
+
case 4006:
|
|
6282
|
+
return "Kicked out of the room, because the room ID changed";
|
|
6283
|
+
default:
|
|
6284
|
+
return "Could not connect to the room";
|
|
6285
|
+
}
|
|
6286
|
+
}
|
|
6287
|
+
case "CREATE_THREAD_ERROR":
|
|
6288
|
+
return "Could not create new thread";
|
|
6289
|
+
case "DELETE_THREAD_ERROR":
|
|
6290
|
+
return "Could not delete thread";
|
|
6291
|
+
case "EDIT_THREAD_METADATA_ERROR":
|
|
6292
|
+
return "Could not edit thread metadata";
|
|
6293
|
+
case "MARK_THREAD_AS_RESOLVED_ERROR":
|
|
6294
|
+
return "Could not mark thread as resolved";
|
|
6295
|
+
case "MARK_THREAD_AS_UNRESOLVED_ERROR":
|
|
6296
|
+
return "Could not mark thread as unresolved";
|
|
6297
|
+
case "CREATE_COMMENT_ERROR":
|
|
6298
|
+
return "Could not create new comment";
|
|
6299
|
+
case "EDIT_COMMENT_ERROR":
|
|
6300
|
+
return "Could not edit comment";
|
|
6301
|
+
case "DELETE_COMMENT_ERROR":
|
|
6302
|
+
return "Could not delete comment";
|
|
6303
|
+
case "ADD_REACTION_ERROR":
|
|
6304
|
+
return "Could not add reaction";
|
|
6305
|
+
case "REMOVE_REACTION_ERROR":
|
|
6306
|
+
return "Could not remove reaction";
|
|
6307
|
+
case "MARK_INBOX_NOTIFICATION_AS_READ_ERROR":
|
|
6308
|
+
return "Could not mark inbox notification as read";
|
|
6309
|
+
case "DELETE_INBOX_NOTIFICATION_ERROR":
|
|
6310
|
+
return "Could not delete inbox notification";
|
|
6311
|
+
case "MARK_ALL_INBOX_NOTIFICATIONS_AS_READ_ERROR":
|
|
6312
|
+
return "Could not mark all inbox notifications as read";
|
|
6313
|
+
case "DELETE_ALL_INBOX_NOTIFICATIONS_ERROR":
|
|
6314
|
+
return "Could not delete all inbox notifications";
|
|
6315
|
+
case "UPDATE_NOTIFICATION_SETTINGS_ERROR":
|
|
6316
|
+
return "Could not update notification settings";
|
|
6317
|
+
default:
|
|
6318
|
+
return assertNever(context, "Unhandled case");
|
|
6319
|
+
}
|
|
6320
|
+
}
|
|
6321
|
+
|
|
6264
6322
|
// src/room.ts
|
|
6265
|
-
var MAX_SOCKET_MESSAGE_SIZE = 1024 * 1024 -
|
|
6323
|
+
var MAX_SOCKET_MESSAGE_SIZE = 1024 * 1024 - 512;
|
|
6266
6324
|
function makeIdFactory(connectionId) {
|
|
6267
6325
|
let count = 0;
|
|
6268
6326
|
return () => `${connectionId}:${count++}`;
|
|
@@ -6425,13 +6483,17 @@ function createRoom(options, config) {
|
|
|
6425
6483
|
managedSocket.events.statusDidChange.subscribe(handleConnectionLossEvent);
|
|
6426
6484
|
managedSocket.events.didConnect.subscribe(onDidConnect);
|
|
6427
6485
|
managedSocket.events.didDisconnect.subscribe(onDidDisconnect);
|
|
6428
|
-
managedSocket.events.
|
|
6429
|
-
|
|
6430
|
-
|
|
6431
|
-
|
|
6432
|
-
|
|
6486
|
+
managedSocket.events.onConnectionError.subscribe(({ message, code }) => {
|
|
6487
|
+
const type = "ROOM_CONNECTION_ERROR";
|
|
6488
|
+
const err = new LiveblocksError(message, { type, code, roomId });
|
|
6489
|
+
const didNotify = config.errorEventSource.notify(err);
|
|
6490
|
+
if (!didNotify) {
|
|
6491
|
+
if (process.env.NODE_ENV !== "production") {
|
|
6492
|
+
error2(
|
|
6493
|
+
`Connection to websocket server closed. Reason: ${message} (code: ${code}).`
|
|
6494
|
+
);
|
|
6495
|
+
}
|
|
6433
6496
|
}
|
|
6434
|
-
eventHub.error.notify(err);
|
|
6435
6497
|
});
|
|
6436
6498
|
const pool = {
|
|
6437
6499
|
roomId: config.roomId,
|
|
@@ -6494,7 +6556,6 @@ function createRoom(options, config) {
|
|
|
6494
6556
|
self: makeEventSource(),
|
|
6495
6557
|
myPresence: makeEventSource(),
|
|
6496
6558
|
others: makeEventSource(),
|
|
6497
|
-
error: makeEventSource(),
|
|
6498
6559
|
storageBatch: makeEventSource(),
|
|
6499
6560
|
history: makeEventSource(),
|
|
6500
6561
|
storageDidLoad: makeEventSource(),
|
|
@@ -6528,24 +6589,82 @@ function createRoom(options, config) {
|
|
|
6528
6589
|
async function createTextVersion() {
|
|
6529
6590
|
return httpClient.createTextVersion({ roomId });
|
|
6530
6591
|
}
|
|
6592
|
+
function* chunkOps(msg) {
|
|
6593
|
+
const { ops, ...rest } = msg;
|
|
6594
|
+
if (ops.length < 2) {
|
|
6595
|
+
throw new Error("Cannot split ops into smaller chunks");
|
|
6596
|
+
}
|
|
6597
|
+
const mid = Math.floor(ops.length / 2);
|
|
6598
|
+
const firstHalf = ops.slice(0, mid);
|
|
6599
|
+
const secondHalf = ops.slice(mid);
|
|
6600
|
+
for (const halfOps of [firstHalf, secondHalf]) {
|
|
6601
|
+
const half = { ops: halfOps, ...rest };
|
|
6602
|
+
const text = JSON.stringify([half]);
|
|
6603
|
+
if (!isTooBigForWebSocket(text)) {
|
|
6604
|
+
yield text;
|
|
6605
|
+
} else {
|
|
6606
|
+
yield* chunkOps(half);
|
|
6607
|
+
}
|
|
6608
|
+
}
|
|
6609
|
+
}
|
|
6610
|
+
function* chunkMessages(messages) {
|
|
6611
|
+
if (messages.length < 2) {
|
|
6612
|
+
if (messages[0].type === 201 /* UPDATE_STORAGE */) {
|
|
6613
|
+
yield* chunkOps(messages[0]);
|
|
6614
|
+
return;
|
|
6615
|
+
} else {
|
|
6616
|
+
throw new Error(
|
|
6617
|
+
"Cannot split into chunks smaller than the allowed message size"
|
|
6618
|
+
);
|
|
6619
|
+
}
|
|
6620
|
+
}
|
|
6621
|
+
const mid = Math.floor(messages.length / 2);
|
|
6622
|
+
const firstHalf = messages.slice(0, mid);
|
|
6623
|
+
const secondHalf = messages.slice(mid);
|
|
6624
|
+
for (const half of [firstHalf, secondHalf]) {
|
|
6625
|
+
const text = JSON.stringify(half);
|
|
6626
|
+
if (!isTooBigForWebSocket(text)) {
|
|
6627
|
+
yield text;
|
|
6628
|
+
} else {
|
|
6629
|
+
yield* chunkMessages(half);
|
|
6630
|
+
}
|
|
6631
|
+
}
|
|
6632
|
+
}
|
|
6633
|
+
function isTooBigForWebSocket(text) {
|
|
6634
|
+
if (text.length * 4 < MAX_SOCKET_MESSAGE_SIZE) {
|
|
6635
|
+
return false;
|
|
6636
|
+
}
|
|
6637
|
+
return new TextEncoder().encode(text).length >= MAX_SOCKET_MESSAGE_SIZE;
|
|
6638
|
+
}
|
|
6531
6639
|
function sendMessages(messages) {
|
|
6532
|
-
const
|
|
6533
|
-
const
|
|
6534
|
-
if (
|
|
6535
|
-
|
|
6536
|
-
|
|
6640
|
+
const strategy = config.largeMessageStrategy ?? "default";
|
|
6641
|
+
const text = JSON.stringify(messages);
|
|
6642
|
+
if (!isTooBigForWebSocket(text)) {
|
|
6643
|
+
return managedSocket.send(text);
|
|
6644
|
+
}
|
|
6645
|
+
switch (strategy) {
|
|
6646
|
+
case "default": {
|
|
6647
|
+
error2("Message is too large for websockets, not sending. Configure largeMessageStrategy option to deal with this.");
|
|
6648
|
+
return;
|
|
6649
|
+
}
|
|
6650
|
+
case "split": {
|
|
6651
|
+
warn("Message is too large for websockets, splitting into smaller chunks");
|
|
6652
|
+
for (const chunk2 of chunkMessages(messages)) {
|
|
6653
|
+
managedSocket.send(chunk2);
|
|
6654
|
+
}
|
|
6655
|
+
return;
|
|
6656
|
+
}
|
|
6657
|
+
case "experimental-fallback-to-http": {
|
|
6658
|
+
warn("Message is too large for websockets, so sending over HTTP instead");
|
|
6659
|
+
const nonce = context.dynamicSessionInfoSig.get()?.nonce ?? raise("Session is not authorized to send message over HTTP");
|
|
6537
6660
|
void httpClient.sendMessages({ roomId, nonce, messages }).then((resp) => {
|
|
6538
6661
|
if (!resp.ok && resp.status === 403) {
|
|
6539
6662
|
managedSocket.reconnect();
|
|
6540
6663
|
}
|
|
6541
6664
|
});
|
|
6542
|
-
warn(
|
|
6543
|
-
"Message was too large for websockets and sent over HTTP instead"
|
|
6544
|
-
);
|
|
6545
6665
|
return;
|
|
6546
6666
|
}
|
|
6547
6667
|
}
|
|
6548
|
-
managedSocket.send(serializedPayload);
|
|
6549
6668
|
}
|
|
6550
6669
|
const self = DerivedSignal.from(
|
|
6551
6670
|
context.staticSessionInfoSig,
|
|
@@ -7334,7 +7453,6 @@ ${Array.from(traces).join("\n\n")}`
|
|
|
7334
7453
|
others: eventHub.others.observable,
|
|
7335
7454
|
self: eventHub.self.observable,
|
|
7336
7455
|
myPresence: eventHub.myPresence.observable,
|
|
7337
|
-
error: eventHub.error.observable,
|
|
7338
7456
|
/** @deprecated */
|
|
7339
7457
|
storage: eventHub.storageBatch.observable,
|
|
7340
7458
|
storageBatch: eventHub.storageBatch.observable,
|
|
@@ -7525,7 +7643,11 @@ ${Array.from(traces).join("\n\n")}`
|
|
|
7525
7643
|
attachmentUrlsStore: httpClient.getOrCreateAttachmentUrlsStore(roomId)
|
|
7526
7644
|
},
|
|
7527
7645
|
id: config.roomId,
|
|
7528
|
-
subscribe: makeClassicSubscribeFn(
|
|
7646
|
+
subscribe: makeClassicSubscribeFn(
|
|
7647
|
+
config.roomId,
|
|
7648
|
+
events,
|
|
7649
|
+
config.errorEventSource
|
|
7650
|
+
),
|
|
7529
7651
|
connect: () => managedSocket.connect(),
|
|
7530
7652
|
reconnect: () => managedSocket.reconnect(),
|
|
7531
7653
|
disconnect: () => managedSocket.disconnect(),
|
|
@@ -7594,7 +7716,7 @@ ${Array.from(traces).join("\n\n")}`
|
|
|
7594
7716
|
{ enumerable: false }
|
|
7595
7717
|
);
|
|
7596
7718
|
}
|
|
7597
|
-
function makeClassicSubscribeFn(events) {
|
|
7719
|
+
function makeClassicSubscribeFn(roomId, events, errorEvents) {
|
|
7598
7720
|
function subscribeToLiveStructureDeeply(node, callback) {
|
|
7599
7721
|
return events.storageBatch.subscribe((updates) => {
|
|
7600
7722
|
const relatedUpdates = updates.filter(
|
|
@@ -7634,8 +7756,13 @@ function makeClassicSubscribeFn(events) {
|
|
|
7634
7756
|
return cb(others, internalEvent);
|
|
7635
7757
|
});
|
|
7636
7758
|
}
|
|
7637
|
-
case "error":
|
|
7638
|
-
return
|
|
7759
|
+
case "error": {
|
|
7760
|
+
return errorEvents.subscribe((err) => {
|
|
7761
|
+
if (err.roomId === roomId) {
|
|
7762
|
+
return callback(err);
|
|
7763
|
+
}
|
|
7764
|
+
});
|
|
7765
|
+
}
|
|
7639
7766
|
case "status":
|
|
7640
7767
|
return events.status.subscribe(callback);
|
|
7641
7768
|
case "lost-connection":
|
|
@@ -7807,7 +7934,8 @@ function createClient(options) {
|
|
|
7807
7934
|
},
|
|
7808
7935
|
enableDebugLogging: clientOptions.enableDebugLogging,
|
|
7809
7936
|
baseUrl,
|
|
7810
|
-
|
|
7937
|
+
errorEventSource: liveblocksErrorSource,
|
|
7938
|
+
largeMessageStrategy: clientOptions.largeMessageStrategy ?? (clientOptions.unstable_fallbackToHTTP ? "experimental-fallback-to-http" : void 0),
|
|
7811
7939
|
unstable_streamData: !!clientOptions.unstable_streamData,
|
|
7812
7940
|
roomHttpClient: httpClient,
|
|
7813
7941
|
createSyncSource
|
|
@@ -7889,6 +8017,7 @@ function createClient(options) {
|
|
|
7889
8017
|
}
|
|
7890
8018
|
const syncStatusSources = [];
|
|
7891
8019
|
const syncStatusSignal = new Signal("synchronized");
|
|
8020
|
+
const liveblocksErrorSource = makeEventSource();
|
|
7892
8021
|
function getSyncStatus() {
|
|
7893
8022
|
const status = syncStatusSignal.get();
|
|
7894
8023
|
return status === "synchronizing" ? status : "synchronized";
|
|
@@ -7940,9 +8069,6 @@ function createClient(options) {
|
|
|
7940
8069
|
markInboxNotificationAsRead: httpClient.markInboxNotificationAsRead,
|
|
7941
8070
|
deleteAllInboxNotifications: httpClient.deleteAllInboxNotifications,
|
|
7942
8071
|
deleteInboxNotification: httpClient.deleteInboxNotification,
|
|
7943
|
-
// Public channel notification settings API
|
|
7944
|
-
getChannelsNotificationSettings: httpClient.getChannelsNotificationSettings,
|
|
7945
|
-
updateChannelsNotificationSettings: httpClient.updateChannelsNotificationSettings,
|
|
7946
8072
|
// Advanced resolvers APIs
|
|
7947
8073
|
resolvers: {
|
|
7948
8074
|
invalidateUsers: invalidateResolvedUsers,
|
|
@@ -7951,6 +8077,7 @@ function createClient(options) {
|
|
|
7951
8077
|
},
|
|
7952
8078
|
getSyncStatus,
|
|
7953
8079
|
events: {
|
|
8080
|
+
error: liveblocksErrorSource,
|
|
7954
8081
|
syncStatus: syncStatusSignal
|
|
7955
8082
|
},
|
|
7956
8083
|
// Internal
|
|
@@ -7966,7 +8093,14 @@ function createClient(options) {
|
|
|
7966
8093
|
httpClient,
|
|
7967
8094
|
// Type-level helper only, it's effectively only an identity-function at runtime
|
|
7968
8095
|
as: () => client,
|
|
7969
|
-
createSyncSource
|
|
8096
|
+
createSyncSource,
|
|
8097
|
+
emitError: (context, cause) => {
|
|
8098
|
+
const error3 = LiveblocksError.from(context, cause);
|
|
8099
|
+
const didNotify = liveblocksErrorSource.notify(error3);
|
|
8100
|
+
if (!didNotify) {
|
|
8101
|
+
error2(error3.message);
|
|
8102
|
+
}
|
|
8103
|
+
}
|
|
7970
8104
|
}
|
|
7971
8105
|
},
|
|
7972
8106
|
kInternal,
|
|
@@ -8131,9 +8265,9 @@ function escapeHtml(value) {
|
|
|
8131
8265
|
var HtmlSafeString = class {
|
|
8132
8266
|
#strings;
|
|
8133
8267
|
#values;
|
|
8134
|
-
constructor(strings,
|
|
8268
|
+
constructor(strings, values) {
|
|
8135
8269
|
this.#strings = strings;
|
|
8136
|
-
this.#values =
|
|
8270
|
+
this.#values = values;
|
|
8137
8271
|
}
|
|
8138
8272
|
toString() {
|
|
8139
8273
|
return this.#strings.reduce((result, str, i) => {
|
|
@@ -8141,8 +8275,8 @@ var HtmlSafeString = class {
|
|
|
8141
8275
|
});
|
|
8142
8276
|
}
|
|
8143
8277
|
};
|
|
8144
|
-
function html(strings, ...
|
|
8145
|
-
return new HtmlSafeString(strings,
|
|
8278
|
+
function html(strings, ...values) {
|
|
8279
|
+
return new HtmlSafeString(strings, values);
|
|
8146
8280
|
}
|
|
8147
8281
|
var markdownEscapables = {
|
|
8148
8282
|
_: "\\_",
|
|
@@ -8187,9 +8321,9 @@ function escapeMarkdown(value) {
|
|
|
8187
8321
|
var MarkdownSafeString = class {
|
|
8188
8322
|
#strings;
|
|
8189
8323
|
#values;
|
|
8190
|
-
constructor(strings,
|
|
8324
|
+
constructor(strings, values) {
|
|
8191
8325
|
this.#strings = strings;
|
|
8192
|
-
this.#values =
|
|
8326
|
+
this.#values = values;
|
|
8193
8327
|
}
|
|
8194
8328
|
toString() {
|
|
8195
8329
|
return this.#strings.reduce((result, str, i) => {
|
|
@@ -8197,8 +8331,8 @@ var MarkdownSafeString = class {
|
|
|
8197
8331
|
});
|
|
8198
8332
|
}
|
|
8199
8333
|
};
|
|
8200
|
-
function markdown(strings, ...
|
|
8201
|
-
return new MarkdownSafeString(strings,
|
|
8334
|
+
function markdown(strings, ...values) {
|
|
8335
|
+
return new MarkdownSafeString(strings, values);
|
|
8202
8336
|
}
|
|
8203
8337
|
function toAbsoluteUrl(url2) {
|
|
8204
8338
|
if (url2.startsWith("http://") || url2.startsWith("https://")) {
|
|
@@ -8802,6 +8936,7 @@ function makePoller(callback, intervalMs, options) {
|
|
|
8802
8936
|
}
|
|
8803
8937
|
doc?.addEventListener("visibilitychange", onVisibilityChange);
|
|
8804
8938
|
win?.addEventListener("online", onVisibilityChange);
|
|
8939
|
+
win?.addEventListener("focus", pollNowIfStale);
|
|
8805
8940
|
fsm.start();
|
|
8806
8941
|
return {
|
|
8807
8942
|
inc,
|
|
@@ -8923,11 +9058,6 @@ var SortedList = class _SortedList {
|
|
|
8923
9058
|
}
|
|
8924
9059
|
};
|
|
8925
9060
|
|
|
8926
|
-
// src/protocol/ChannelsNotificationSettings.ts
|
|
8927
|
-
function isChannelNotificationSettingEnabled(setting) {
|
|
8928
|
-
return values(setting).every((enabled) => enabled === true);
|
|
8929
|
-
}
|
|
8930
|
-
|
|
8931
9061
|
// src/types/Others.ts
|
|
8932
9062
|
var TextEditorType = /* @__PURE__ */ ((TextEditorType2) => {
|
|
8933
9063
|
TextEditorType2["Lexical"] = "lexical";
|
|
@@ -8949,6 +9079,7 @@ export {
|
|
|
8949
9079
|
LiveList,
|
|
8950
9080
|
LiveMap,
|
|
8951
9081
|
LiveObject,
|
|
9082
|
+
LiveblocksError,
|
|
8952
9083
|
MutableSignal,
|
|
8953
9084
|
NotificationsApiError,
|
|
8954
9085
|
OpCode,
|
|
@@ -8982,14 +9113,12 @@ export {
|
|
|
8982
9113
|
deprecate,
|
|
8983
9114
|
deprecateIf,
|
|
8984
9115
|
detectDupes,
|
|
8985
|
-
entries,
|
|
8986
9116
|
errorIf,
|
|
8987
9117
|
freeze,
|
|
8988
9118
|
generateCommentUrl,
|
|
8989
9119
|
getMentionedIdsFromCommentBody,
|
|
8990
9120
|
html,
|
|
8991
9121
|
htmlSafe,
|
|
8992
|
-
isChannelNotificationSettingEnabled,
|
|
8993
9122
|
isChildCrdt,
|
|
8994
9123
|
isCommentBodyLink,
|
|
8995
9124
|
isCommentBodyMention,
|
|
@@ -9002,7 +9131,6 @@ export {
|
|
|
9002
9131
|
isRootCrdt,
|
|
9003
9132
|
isStartsWithOperator,
|
|
9004
9133
|
kInternal,
|
|
9005
|
-
keys,
|
|
9006
9134
|
legacy_patchImmutableObject,
|
|
9007
9135
|
lsonToJson,
|
|
9008
9136
|
makeEventSource,
|
|
@@ -9023,7 +9151,6 @@ export {
|
|
|
9023
9151
|
toAbsoluteUrl,
|
|
9024
9152
|
toPlainLson,
|
|
9025
9153
|
tryParseJson,
|
|
9026
|
-
unstringify,
|
|
9027
9154
|
url,
|
|
9028
9155
|
urljoin,
|
|
9029
9156
|
wait,
|