@liveblocks/core 2.15.2 → 2.16.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 +396 -305
- package/dist/index.d.ts +396 -305
- package/dist/index.js +311 -200
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +204 -93
- package/dist/index.mjs.map +1 -1
- package/package.json +4 -4
package/dist/index.mjs
CHANGED
|
@@ -6,7 +6,7 @@ var __export = (target, all) => {
|
|
|
6
6
|
|
|
7
7
|
// src/version.ts
|
|
8
8
|
var PKG_NAME = "@liveblocks/core";
|
|
9
|
-
var PKG_VERSION = "2.
|
|
9
|
+
var PKG_VERSION = "2.16.0-rc1";
|
|
10
10
|
var PKG_FORMAT = "esm";
|
|
11
11
|
|
|
12
12
|
// src/dupe-detection.ts
|
|
@@ -166,13 +166,18 @@ 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);
|
|
172
180
|
}
|
|
173
|
-
function isPlainObject(blob) {
|
|
174
|
-
return blob !== null && typeof blob === "object" && Object.prototype.toString.call(blob) === "[object Object]";
|
|
175
|
-
}
|
|
176
181
|
function entries(obj) {
|
|
177
182
|
return Object.entries(obj);
|
|
178
183
|
}
|
|
@@ -254,13 +259,48 @@ function memoizeOnSuccess(factoryFn) {
|
|
|
254
259
|
}
|
|
255
260
|
|
|
256
261
|
// src/lib/autoRetry.ts
|
|
257
|
-
var HttpError = class extends Error {
|
|
258
|
-
|
|
262
|
+
var HttpError = class _HttpError extends Error {
|
|
263
|
+
response;
|
|
264
|
+
details;
|
|
265
|
+
constructor(message, response, details) {
|
|
259
266
|
super(message);
|
|
260
|
-
this.
|
|
261
|
-
this.
|
|
267
|
+
this.name = "HttpError";
|
|
268
|
+
this.response = response;
|
|
262
269
|
this.details = details;
|
|
263
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
|
+
}
|
|
264
304
|
};
|
|
265
305
|
var DONT_RETRY_4XX = (x) => x instanceof HttpError && x.status >= 400 && x.status < 500;
|
|
266
306
|
async function autoRetry(promiseFn, maxTries, backoff, shouldStopRetrying = DONT_RETRY_4XX) {
|
|
@@ -326,7 +366,12 @@ function makeEventSource() {
|
|
|
326
366
|
}).finally(() => unsub?.());
|
|
327
367
|
}
|
|
328
368
|
function notify(event) {
|
|
329
|
-
|
|
369
|
+
let called = false;
|
|
370
|
+
for (const callback of _observers) {
|
|
371
|
+
callback(event);
|
|
372
|
+
called = true;
|
|
373
|
+
}
|
|
374
|
+
return called;
|
|
330
375
|
}
|
|
331
376
|
function count() {
|
|
332
377
|
return _observers.size;
|
|
@@ -367,8 +412,9 @@ function makeBufferableEventSource() {
|
|
|
367
412
|
function notifyOrBuffer(event) {
|
|
368
413
|
if (_buffer !== null) {
|
|
369
414
|
_buffer.push(event);
|
|
415
|
+
return false;
|
|
370
416
|
} else {
|
|
371
|
-
eventSource2.notify(event);
|
|
417
|
+
return eventSource2.notify(event);
|
|
372
418
|
}
|
|
373
419
|
}
|
|
374
420
|
return {
|
|
@@ -673,32 +719,15 @@ var MutableSignal = class extends AbstractSignal {
|
|
|
673
719
|
};
|
|
674
720
|
|
|
675
721
|
// src/lib/stringify.ts
|
|
676
|
-
var EXPLICIT_UNDEFINED_PLACEHOLDER = "_explicit_undefined";
|
|
677
722
|
function replacer(_key, value) {
|
|
678
723
|
return value !== null && typeof value === "object" && !Array.isArray(value) ? Object.keys(value).sort().reduce((sorted, key) => {
|
|
679
724
|
sorted[key] = value[key];
|
|
680
725
|
return sorted;
|
|
681
|
-
}, {}) : value
|
|
682
|
-
}
|
|
683
|
-
function reviver(key, value) {
|
|
684
|
-
if (!key && value === EXPLICIT_UNDEFINED_PLACEHOLDER) {
|
|
685
|
-
return void 0;
|
|
686
|
-
}
|
|
687
|
-
if (value && typeof value === "object") {
|
|
688
|
-
for (const k in value) {
|
|
689
|
-
if (value[k] === EXPLICIT_UNDEFINED_PLACEHOLDER) {
|
|
690
|
-
Object.defineProperty(value, k, { value: void 0 });
|
|
691
|
-
}
|
|
692
|
-
}
|
|
693
|
-
}
|
|
694
|
-
return value;
|
|
726
|
+
}, {}) : value;
|
|
695
727
|
}
|
|
696
728
|
function stringify(value) {
|
|
697
729
|
return JSON.stringify(value, replacer);
|
|
698
730
|
}
|
|
699
|
-
function unstringify(value) {
|
|
700
|
-
return JSON.parse(value, reviver);
|
|
701
|
-
}
|
|
702
731
|
|
|
703
732
|
// src/lib/batch.ts
|
|
704
733
|
var DEFAULT_SIZE = 50;
|
|
@@ -928,10 +957,12 @@ function objectToQuery(obj) {
|
|
|
928
957
|
}
|
|
929
958
|
if (isSimpleValue(value)) {
|
|
930
959
|
keyValuePairs.push([key, value]);
|
|
931
|
-
} else if (
|
|
932
|
-
|
|
933
|
-
|
|
934
|
-
|
|
960
|
+
} else if (isPlainObject(value)) {
|
|
961
|
+
if (isStartsWithOperator(value)) {
|
|
962
|
+
keyValuePairsWithOperator.push([key, value]);
|
|
963
|
+
} else {
|
|
964
|
+
indexedKeys.push([key, value]);
|
|
965
|
+
}
|
|
935
966
|
}
|
|
936
967
|
});
|
|
937
968
|
filterList = [
|
|
@@ -948,7 +979,7 @@ function objectToQuery(obj) {
|
|
|
948
979
|
}
|
|
949
980
|
if (isSimpleValue(nestedValue)) {
|
|
950
981
|
nKeyValuePairs.push([formatFilterKey(key, nestedKey), nestedValue]);
|
|
951
|
-
} else if (
|
|
982
|
+
} else if (isStartsWithOperator(nestedValue)) {
|
|
952
983
|
nKeyValuePairsWithOperator.push([
|
|
953
984
|
formatFilterKey(key, nestedKey),
|
|
954
985
|
nestedValue
|
|
@@ -961,9 +992,7 @@ function objectToQuery(obj) {
|
|
|
961
992
|
...getFiltersFromKeyValuePairsWithOperator(nKeyValuePairsWithOperator)
|
|
962
993
|
];
|
|
963
994
|
});
|
|
964
|
-
return filterList.map(
|
|
965
|
-
({ key, operator, value }) => formatFilter(key, operator, formatFilterValue(value))
|
|
966
|
-
).join(" AND ");
|
|
995
|
+
return filterList.map(({ key, operator, value }) => `${key}${operator}${quote(value)}`).join(" ");
|
|
967
996
|
}
|
|
968
997
|
var getFiltersFromKeyValuePairs = (keyValuePairs) => {
|
|
969
998
|
const filters = [];
|
|
@@ -990,38 +1019,20 @@ var getFiltersFromKeyValuePairsWithOperator = (keyValuePairsWithOperator) => {
|
|
|
990
1019
|
return filters;
|
|
991
1020
|
};
|
|
992
1021
|
var isSimpleValue = (value) => {
|
|
993
|
-
|
|
994
|
-
return true;
|
|
995
|
-
}
|
|
996
|
-
return false;
|
|
997
|
-
};
|
|
998
|
-
var isValueWithOperator = (value) => {
|
|
999
|
-
if (typeof value === "object" && value !== null && "startsWith" in value) {
|
|
1000
|
-
return true;
|
|
1001
|
-
}
|
|
1002
|
-
return false;
|
|
1003
|
-
};
|
|
1004
|
-
var formatFilter = (key, operator, value) => {
|
|
1005
|
-
return `${key}${operator}${value}`;
|
|
1022
|
+
return typeof value === "string" || typeof value === "number" || typeof value === "boolean" || value === null;
|
|
1006
1023
|
};
|
|
1007
1024
|
var formatFilterKey = (key, nestedKey) => {
|
|
1008
1025
|
if (nestedKey) {
|
|
1009
|
-
return `${key}[${
|
|
1026
|
+
return `${key}[${quote(nestedKey)}]`;
|
|
1010
1027
|
}
|
|
1011
1028
|
return key;
|
|
1012
1029
|
};
|
|
1013
|
-
var formatFilterValue = (value) => {
|
|
1014
|
-
if (typeof value === "string") {
|
|
1015
|
-
if (isStringEmpty(value)) {
|
|
1016
|
-
throw new Error("Value cannot be empty");
|
|
1017
|
-
}
|
|
1018
|
-
return JSON.stringify(value);
|
|
1019
|
-
}
|
|
1020
|
-
return value.toString();
|
|
1021
|
-
};
|
|
1022
1030
|
var isStringEmpty = (value) => {
|
|
1023
1031
|
return !value || value.toString().trim() === "";
|
|
1024
1032
|
};
|
|
1033
|
+
function quote(value) {
|
|
1034
|
+
return typeof value !== "string" || value.includes("'") ? JSON.stringify(value) : `'${value}'`;
|
|
1035
|
+
}
|
|
1025
1036
|
|
|
1026
1037
|
// src/lib/url.ts
|
|
1027
1038
|
function toURLSearchParams(params) {
|
|
@@ -1846,14 +1857,7 @@ var HttpClient = class {
|
|
|
1846
1857
|
async #fetch(endpoint, authValue, options, params) {
|
|
1847
1858
|
const response = await this.#rawFetch(endpoint, authValue, options, params);
|
|
1848
1859
|
if (!response.ok) {
|
|
1849
|
-
|
|
1850
|
-
try {
|
|
1851
|
-
const errorBody = await response.json();
|
|
1852
|
-
error3 = new HttpError(errorBody.message, response.status, errorBody);
|
|
1853
|
-
} catch {
|
|
1854
|
-
error3 = new HttpError(response.statusText, response.status);
|
|
1855
|
-
}
|
|
1856
|
-
throw error3;
|
|
1860
|
+
throw await HttpError.fromResponse(response);
|
|
1857
1861
|
}
|
|
1858
1862
|
let body;
|
|
1859
1863
|
try {
|
|
@@ -2480,6 +2484,7 @@ function toNewConnectionStatus(machine) {
|
|
|
2480
2484
|
return machine.context.successCount > 0 ? "reconnecting" : "connecting";
|
|
2481
2485
|
case "@idle.failed":
|
|
2482
2486
|
return "disconnected";
|
|
2487
|
+
// istanbul ignore next
|
|
2483
2488
|
default:
|
|
2484
2489
|
return assertNever(state, "Unknown state");
|
|
2485
2490
|
}
|
|
@@ -2496,13 +2501,6 @@ var StopRetrying = class extends Error {
|
|
|
2496
2501
|
super(reason);
|
|
2497
2502
|
}
|
|
2498
2503
|
};
|
|
2499
|
-
var LiveblocksError = class extends Error {
|
|
2500
|
-
/** @internal */
|
|
2501
|
-
constructor(message, code) {
|
|
2502
|
-
super(message);
|
|
2503
|
-
this.code = code;
|
|
2504
|
-
}
|
|
2505
|
-
};
|
|
2506
2504
|
function nextBackoffDelay(currentDelay, delays) {
|
|
2507
2505
|
return delays.find((delay) => delay > currentDelay) ?? delays[delays.length - 1];
|
|
2508
2506
|
}
|
|
@@ -2612,11 +2610,10 @@ var assign = (patch) => (ctx) => ctx.patch(patch);
|
|
|
2612
2610
|
function createConnectionStateMachine(delegates, options) {
|
|
2613
2611
|
const onMessage = makeBufferableEventSource();
|
|
2614
2612
|
onMessage.pause();
|
|
2615
|
-
const
|
|
2616
|
-
function fireErrorEvent(
|
|
2613
|
+
const onConnectionError = makeEventSource();
|
|
2614
|
+
function fireErrorEvent(message, code) {
|
|
2617
2615
|
return () => {
|
|
2618
|
-
|
|
2619
|
-
onLiveblocksError.notify(err);
|
|
2616
|
+
onConnectionError.notify({ message, code });
|
|
2620
2617
|
};
|
|
2621
2618
|
}
|
|
2622
2619
|
const initialContext = {
|
|
@@ -2974,7 +2971,7 @@ function createConnectionStateMachine(delegates, options) {
|
|
|
2974
2971
|
didConnect,
|
|
2975
2972
|
didDisconnect,
|
|
2976
2973
|
onMessage: onMessage.observable,
|
|
2977
|
-
|
|
2974
|
+
onConnectionError: onConnectionError.observable
|
|
2978
2975
|
}
|
|
2979
2976
|
};
|
|
2980
2977
|
}
|
|
@@ -3360,6 +3357,12 @@ function setupDevTools(getAllRooms) {
|
|
|
3360
3357
|
_devtoolsSetupHasRun = true;
|
|
3361
3358
|
onMessageFromPanel.subscribe((msg) => {
|
|
3362
3359
|
switch (msg.msg) {
|
|
3360
|
+
// When a devtool panel sends an explicit "connect" message back to this
|
|
3361
|
+
// live running client (in response to the "wake-up-devtools" message,
|
|
3362
|
+
// or when the devtool panel is opened for the first time), it means that it's okay to
|
|
3363
|
+
// start emitting messages.
|
|
3364
|
+
// Before this explicit acknowledgement, any call to sendToPanel() will
|
|
3365
|
+
// be a no-op.
|
|
3363
3366
|
case "connect": {
|
|
3364
3367
|
activateBridge(true);
|
|
3365
3368
|
for (const roomId of getAllRooms()) {
|
|
@@ -3500,6 +3503,8 @@ function linkDevTools(roomId, room) {
|
|
|
3500
3503
|
// roomChannelListeners registry
|
|
3501
3504
|
onMessageFromPanel.subscribe((msg) => {
|
|
3502
3505
|
switch (msg.msg) {
|
|
3506
|
+
// Sent by the devtool panel when it wants to receive the sync stream
|
|
3507
|
+
// for a room
|
|
3503
3508
|
case "room::subscribe": {
|
|
3504
3509
|
if (msg.roomId === roomId) {
|
|
3505
3510
|
startSyncStream(room);
|
|
@@ -6230,6 +6235,83 @@ var ManagedOthers = class {
|
|
|
6230
6235
|
}
|
|
6231
6236
|
};
|
|
6232
6237
|
|
|
6238
|
+
// src/types/LiveblocksError.ts
|
|
6239
|
+
var LiveblocksError = class _LiveblocksError extends Error {
|
|
6240
|
+
context;
|
|
6241
|
+
constructor(message, context, cause) {
|
|
6242
|
+
super(message, { cause });
|
|
6243
|
+
this.context = context;
|
|
6244
|
+
this.name = "LiveblocksError";
|
|
6245
|
+
}
|
|
6246
|
+
/** Convenience accessor for error.context.roomId (if available) */
|
|
6247
|
+
get roomId() {
|
|
6248
|
+
return this.context.roomId;
|
|
6249
|
+
}
|
|
6250
|
+
/** @deprecated Prefer using `context.code` instead, to enable type narrowing */
|
|
6251
|
+
get code() {
|
|
6252
|
+
return this.context.code;
|
|
6253
|
+
}
|
|
6254
|
+
/**
|
|
6255
|
+
* Creates a LiveblocksError from a generic error, by attaching Liveblocks
|
|
6256
|
+
* contextual information like room ID, thread ID, etc.
|
|
6257
|
+
*/
|
|
6258
|
+
static from(context, cause) {
|
|
6259
|
+
return new _LiveblocksError(
|
|
6260
|
+
defaultMessageFromContext(context),
|
|
6261
|
+
context,
|
|
6262
|
+
cause
|
|
6263
|
+
);
|
|
6264
|
+
}
|
|
6265
|
+
};
|
|
6266
|
+
function defaultMessageFromContext(context) {
|
|
6267
|
+
switch (context.type) {
|
|
6268
|
+
case "ROOM_CONNECTION_ERROR": {
|
|
6269
|
+
switch (context.code) {
|
|
6270
|
+
case 4001:
|
|
6271
|
+
return "Not allowed to connect to the room";
|
|
6272
|
+
case 4005:
|
|
6273
|
+
return "Room is already full";
|
|
6274
|
+
case 4006:
|
|
6275
|
+
return "Kicked out of the room, because the room ID changed";
|
|
6276
|
+
default:
|
|
6277
|
+
return "Could not connect to the room";
|
|
6278
|
+
}
|
|
6279
|
+
}
|
|
6280
|
+
case "CREATE_THREAD_ERROR":
|
|
6281
|
+
return "Could not create new thread";
|
|
6282
|
+
case "DELETE_THREAD_ERROR":
|
|
6283
|
+
return "Could not delete thread";
|
|
6284
|
+
case "EDIT_THREAD_METADATA_ERROR":
|
|
6285
|
+
return "Could not edit thread metadata";
|
|
6286
|
+
case "MARK_THREAD_AS_RESOLVED_ERROR":
|
|
6287
|
+
return "Could not mark thread as resolved";
|
|
6288
|
+
case "MARK_THREAD_AS_UNRESOLVED_ERROR":
|
|
6289
|
+
return "Could not mark thread as unresolved";
|
|
6290
|
+
case "CREATE_COMMENT_ERROR":
|
|
6291
|
+
return "Could not create new comment";
|
|
6292
|
+
case "EDIT_COMMENT_ERROR":
|
|
6293
|
+
return "Could not edit comment";
|
|
6294
|
+
case "DELETE_COMMENT_ERROR":
|
|
6295
|
+
return "Could not delete comment";
|
|
6296
|
+
case "ADD_REACTION_ERROR":
|
|
6297
|
+
return "Could not add reaction";
|
|
6298
|
+
case "REMOVE_REACTION_ERROR":
|
|
6299
|
+
return "Could not remove reaction";
|
|
6300
|
+
case "MARK_INBOX_NOTIFICATION_AS_READ_ERROR":
|
|
6301
|
+
return "Could not mark inbox notification as read";
|
|
6302
|
+
case "DELETE_INBOX_NOTIFICATION_ERROR":
|
|
6303
|
+
return "Could not delete inbox notification";
|
|
6304
|
+
case "MARK_ALL_INBOX_NOTIFICATIONS_AS_READ_ERROR":
|
|
6305
|
+
return "Could not mark all inbox notifications as read";
|
|
6306
|
+
case "DELETE_ALL_INBOX_NOTIFICATIONS_ERROR":
|
|
6307
|
+
return "Could not delete all inbox notifications";
|
|
6308
|
+
case "UPDATE_NOTIFICATION_SETTINGS_ERROR":
|
|
6309
|
+
return "Could not update notification settings";
|
|
6310
|
+
default:
|
|
6311
|
+
return assertNever(context, "Unhandled case");
|
|
6312
|
+
}
|
|
6313
|
+
}
|
|
6314
|
+
|
|
6233
6315
|
// src/room.ts
|
|
6234
6316
|
var MAX_SOCKET_MESSAGE_SIZE = 1024 * 1024 - 1024;
|
|
6235
6317
|
function makeIdFactory(connectionId) {
|
|
@@ -6394,13 +6476,17 @@ function createRoom(options, config) {
|
|
|
6394
6476
|
managedSocket.events.statusDidChange.subscribe(handleConnectionLossEvent);
|
|
6395
6477
|
managedSocket.events.didConnect.subscribe(onDidConnect);
|
|
6396
6478
|
managedSocket.events.didDisconnect.subscribe(onDidDisconnect);
|
|
6397
|
-
managedSocket.events.
|
|
6398
|
-
|
|
6399
|
-
|
|
6400
|
-
|
|
6401
|
-
|
|
6479
|
+
managedSocket.events.onConnectionError.subscribe(({ message, code }) => {
|
|
6480
|
+
const type = "ROOM_CONNECTION_ERROR";
|
|
6481
|
+
const err = new LiveblocksError(message, { type, code, roomId });
|
|
6482
|
+
const didNotify = config.errorEventSource.notify(err);
|
|
6483
|
+
if (!didNotify) {
|
|
6484
|
+
if (process.env.NODE_ENV !== "production") {
|
|
6485
|
+
error2(
|
|
6486
|
+
`Connection to websocket server closed. Reason: ${message} (code: ${code}).`
|
|
6487
|
+
);
|
|
6488
|
+
}
|
|
6402
6489
|
}
|
|
6403
|
-
eventHub.error.notify(err);
|
|
6404
6490
|
});
|
|
6405
6491
|
const pool = {
|
|
6406
6492
|
roomId: config.roomId,
|
|
@@ -6463,7 +6549,6 @@ function createRoom(options, config) {
|
|
|
6463
6549
|
self: makeEventSource(),
|
|
6464
6550
|
myPresence: makeEventSource(),
|
|
6465
6551
|
others: makeEventSource(),
|
|
6466
|
-
error: makeEventSource(),
|
|
6467
6552
|
storageBatch: makeEventSource(),
|
|
6468
6553
|
history: makeEventSource(),
|
|
6469
6554
|
storageDidLoad: makeEventSource(),
|
|
@@ -6942,6 +7027,7 @@ function createRoom(options, config) {
|
|
|
6942
7027
|
processInitialStorage(message);
|
|
6943
7028
|
break;
|
|
6944
7029
|
}
|
|
7030
|
+
// Write event
|
|
6945
7031
|
case 201 /* UPDATE_STORAGE */: {
|
|
6946
7032
|
const applyResult = applyOps(message.ops, false);
|
|
6947
7033
|
for (const [key, value] of applyResult.updates.storageUpdates) {
|
|
@@ -6952,6 +7038,11 @@ function createRoom(options, config) {
|
|
|
6952
7038
|
}
|
|
6953
7039
|
break;
|
|
6954
7040
|
}
|
|
7041
|
+
// Receiving a RejectedOps message in the client means that the server is no
|
|
7042
|
+
// longer in sync with the client. Trying to synchronize the client again by
|
|
7043
|
+
// rolling back particular Ops may be hard/impossible. It's fine to not try and
|
|
7044
|
+
// accept the out-of-sync reality and throw an error. We look at this kind of bug
|
|
7045
|
+
// as a developer-owned bug. In production, these errors are not expected to happen.
|
|
6955
7046
|
case 299 /* REJECT_STORAGE_OP */: {
|
|
6956
7047
|
errorWithTitle(
|
|
6957
7048
|
"Storage mutation rejection error",
|
|
@@ -7295,7 +7386,6 @@ ${Array.from(traces).join("\n\n")}`
|
|
|
7295
7386
|
others: eventHub.others.observable,
|
|
7296
7387
|
self: eventHub.self.observable,
|
|
7297
7388
|
myPresence: eventHub.myPresence.observable,
|
|
7298
|
-
error: eventHub.error.observable,
|
|
7299
7389
|
/** @deprecated */
|
|
7300
7390
|
storage: eventHub.storageBatch.observable,
|
|
7301
7391
|
storageBatch: eventHub.storageBatch.observable,
|
|
@@ -7486,7 +7576,11 @@ ${Array.from(traces).join("\n\n")}`
|
|
|
7486
7576
|
attachmentUrlsStore: httpClient.getOrCreateAttachmentUrlsStore(roomId)
|
|
7487
7577
|
},
|
|
7488
7578
|
id: config.roomId,
|
|
7489
|
-
subscribe: makeClassicSubscribeFn(
|
|
7579
|
+
subscribe: makeClassicSubscribeFn(
|
|
7580
|
+
config.roomId,
|
|
7581
|
+
events,
|
|
7582
|
+
config.errorEventSource
|
|
7583
|
+
),
|
|
7490
7584
|
connect: () => managedSocket.connect(),
|
|
7491
7585
|
reconnect: () => managedSocket.reconnect(),
|
|
7492
7586
|
disconnect: () => managedSocket.disconnect(),
|
|
@@ -7555,7 +7649,7 @@ ${Array.from(traces).join("\n\n")}`
|
|
|
7555
7649
|
{ enumerable: false }
|
|
7556
7650
|
);
|
|
7557
7651
|
}
|
|
7558
|
-
function makeClassicSubscribeFn(events) {
|
|
7652
|
+
function makeClassicSubscribeFn(roomId, events, errorEvents) {
|
|
7559
7653
|
function subscribeToLiveStructureDeeply(node, callback) {
|
|
7560
7654
|
return events.storageBatch.subscribe((updates) => {
|
|
7561
7655
|
const relatedUpdates = updates.filter(
|
|
@@ -7595,8 +7689,13 @@ function makeClassicSubscribeFn(events) {
|
|
|
7595
7689
|
return cb(others, internalEvent);
|
|
7596
7690
|
});
|
|
7597
7691
|
}
|
|
7598
|
-
case "error":
|
|
7599
|
-
return
|
|
7692
|
+
case "error": {
|
|
7693
|
+
return errorEvents.subscribe((err) => {
|
|
7694
|
+
if (err.roomId === roomId) {
|
|
7695
|
+
return callback(err);
|
|
7696
|
+
}
|
|
7697
|
+
});
|
|
7698
|
+
}
|
|
7600
7699
|
case "status":
|
|
7601
7700
|
return events.status.subscribe(callback);
|
|
7602
7701
|
case "lost-connection":
|
|
@@ -7613,6 +7712,7 @@ function makeClassicSubscribeFn(events) {
|
|
|
7613
7712
|
return events.comments.subscribe(
|
|
7614
7713
|
callback
|
|
7615
7714
|
);
|
|
7715
|
+
// istanbul ignore next
|
|
7616
7716
|
default:
|
|
7617
7717
|
return assertNever(
|
|
7618
7718
|
first,
|
|
@@ -7767,6 +7867,7 @@ function createClient(options) {
|
|
|
7767
7867
|
},
|
|
7768
7868
|
enableDebugLogging: clientOptions.enableDebugLogging,
|
|
7769
7869
|
baseUrl,
|
|
7870
|
+
errorEventSource: liveblocksErrorSource,
|
|
7770
7871
|
unstable_fallbackToHTTP: !!clientOptions.unstable_fallbackToHTTP,
|
|
7771
7872
|
unstable_streamData: !!clientOptions.unstable_streamData,
|
|
7772
7873
|
roomHttpClient: httpClient,
|
|
@@ -7849,6 +7950,7 @@ function createClient(options) {
|
|
|
7849
7950
|
}
|
|
7850
7951
|
const syncStatusSources = [];
|
|
7851
7952
|
const syncStatusSignal = new Signal("synchronized");
|
|
7953
|
+
const liveblocksErrorSource = makeEventSource();
|
|
7852
7954
|
function getSyncStatus() {
|
|
7853
7955
|
const status = syncStatusSignal.get();
|
|
7854
7956
|
return status === "synchronizing" ? status : "synchronized";
|
|
@@ -7908,6 +8010,7 @@ function createClient(options) {
|
|
|
7908
8010
|
},
|
|
7909
8011
|
getSyncStatus,
|
|
7910
8012
|
events: {
|
|
8013
|
+
error: liveblocksErrorSource,
|
|
7911
8014
|
syncStatus: syncStatusSignal
|
|
7912
8015
|
},
|
|
7913
8016
|
// Internal
|
|
@@ -7923,7 +8026,14 @@ function createClient(options) {
|
|
|
7923
8026
|
httpClient,
|
|
7924
8027
|
// Type-level helper only, it's effectively only an identity-function at runtime
|
|
7925
8028
|
as: () => client,
|
|
7926
|
-
createSyncSource
|
|
8029
|
+
createSyncSource,
|
|
8030
|
+
emitError: (context, cause) => {
|
|
8031
|
+
const error3 = LiveblocksError.from(context, cause);
|
|
8032
|
+
const didNotify = liveblocksErrorSource.notify(error3);
|
|
8033
|
+
if (!didNotify) {
|
|
8034
|
+
error2(error3.message);
|
|
8035
|
+
}
|
|
8036
|
+
}
|
|
7927
8037
|
}
|
|
7928
8038
|
},
|
|
7929
8039
|
kInternal,
|
|
@@ -8901,6 +9011,7 @@ export {
|
|
|
8901
9011
|
LiveList,
|
|
8902
9012
|
LiveMap,
|
|
8903
9013
|
LiveObject,
|
|
9014
|
+
LiveblocksError,
|
|
8904
9015
|
MutableSignal,
|
|
8905
9016
|
NotificationsApiError,
|
|
8906
9017
|
OpCode,
|
|
@@ -8950,6 +9061,7 @@ export {
|
|
|
8950
9061
|
isLiveNode,
|
|
8951
9062
|
isPlainObject,
|
|
8952
9063
|
isRootCrdt,
|
|
9064
|
+
isStartsWithOperator,
|
|
8953
9065
|
kInternal,
|
|
8954
9066
|
legacy_patchImmutableObject,
|
|
8955
9067
|
lsonToJson,
|
|
@@ -8971,7 +9083,6 @@ export {
|
|
|
8971
9083
|
toAbsoluteUrl,
|
|
8972
9084
|
toPlainLson,
|
|
8973
9085
|
tryParseJson,
|
|
8974
|
-
unstringify,
|
|
8975
9086
|
url,
|
|
8976
9087
|
urljoin,
|
|
8977
9088
|
wait,
|