@liveblocks/core 1.0.6-test3 → 1.0.7-test1
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.ts +81 -15
- package/dist/index.js +304 -303
- package/package.json +1 -1
package/dist/index.d.ts
CHANGED
|
@@ -1236,20 +1236,10 @@ declare function errorIf(condition: unknown, message: string): void;
|
|
|
1236
1236
|
*/
|
|
1237
1237
|
declare const freeze: typeof Object.freeze;
|
|
1238
1238
|
|
|
1239
|
-
declare
|
|
1240
|
-
declare
|
|
1241
|
-
|
|
1242
|
-
|
|
1243
|
-
* Shallowly compares two given values.
|
|
1244
|
-
*
|
|
1245
|
-
* - Two simple values are considered equal if they're strictly equal
|
|
1246
|
-
* - Two arrays are considered equal if their members are strictly equal
|
|
1247
|
-
* - Two objects are considered equal if their values are strictly equal
|
|
1248
|
-
*
|
|
1249
|
-
* Testing goes one level deep.
|
|
1250
|
-
*/
|
|
1251
|
-
declare function shallow(a: unknown, b: unknown): boolean;
|
|
1252
|
-
|
|
1239
|
+
declare const brand: unique symbol;
|
|
1240
|
+
declare type Brand<T, TBrand extends string> = T & {
|
|
1241
|
+
[brand]: TBrand;
|
|
1242
|
+
};
|
|
1253
1243
|
declare function isPlainObject(blob: unknown): blob is {
|
|
1254
1244
|
[key: string]: unknown;
|
|
1255
1245
|
};
|
|
@@ -1263,6 +1253,82 @@ declare function tryParseJson(rawMessage: string): Json | undefined;
|
|
|
1263
1253
|
*/
|
|
1264
1254
|
declare function b64decode(b64value: string): string;
|
|
1265
1255
|
|
|
1256
|
+
/**
|
|
1257
|
+
* Positions, aka the Pos type, are efficient encodings of "positions" in
|
|
1258
|
+
* a list, using the following printable subset of the ASCII alphabet:
|
|
1259
|
+
*
|
|
1260
|
+
* !"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~
|
|
1261
|
+
* ^ ^
|
|
1262
|
+
* Lowest digit Highest digit
|
|
1263
|
+
*
|
|
1264
|
+
* Each Pos is a sequence of characters from the above alphabet, conceptually
|
|
1265
|
+
* codifying a floating point number 0 < n < 1. For example, the string "31007"
|
|
1266
|
+
* would be used to represent the number 0.31007, except that this
|
|
1267
|
+
* representation uses base 96.
|
|
1268
|
+
*
|
|
1269
|
+
* 0 ≃ ' ' (lowest digit)
|
|
1270
|
+
* 1 ≃ '!'
|
|
1271
|
+
* 2 ≃ '"'
|
|
1272
|
+
* ...
|
|
1273
|
+
* 9 ≃ '~' (highest digit)
|
|
1274
|
+
*
|
|
1275
|
+
* So think:
|
|
1276
|
+
* '!' ≃ 0.1
|
|
1277
|
+
* '"' ≃ 0.2
|
|
1278
|
+
* '!"~' ≃ 0.129
|
|
1279
|
+
*
|
|
1280
|
+
* Three rules:
|
|
1281
|
+
* - All "characters" in the string should be valid digits (from the above
|
|
1282
|
+
* alphabet)
|
|
1283
|
+
* - The value 0.0 is not a valid Pos value
|
|
1284
|
+
* - A Pos cannot have trailing "zeroes"
|
|
1285
|
+
*
|
|
1286
|
+
* This representation has the following benefits:
|
|
1287
|
+
*
|
|
1288
|
+
* 1. It's always possible to get a number that lies before, after, or between
|
|
1289
|
+
* two arbitrary Pos values.
|
|
1290
|
+
* 2. Pos values can be compared using normal string comparison.
|
|
1291
|
+
*
|
|
1292
|
+
* Some examples:
|
|
1293
|
+
* - '!' < '"' (like how .1 < .2)
|
|
1294
|
+
* - '!' < '~' (like how .1 < .9)
|
|
1295
|
+
* - '!!' < '!~' (like how .11 < .19)
|
|
1296
|
+
* - '~!' < '~~' (like how .91 < .99)
|
|
1297
|
+
* - '~' < '~!' (like how .9 < .91)
|
|
1298
|
+
* - '!!' < '!O' (like how .1 < .5)
|
|
1299
|
+
* - '!O' < '!~' (like how .5 < .9)
|
|
1300
|
+
*
|
|
1301
|
+
*/
|
|
1302
|
+
|
|
1303
|
+
/**
|
|
1304
|
+
* A valid/verified "position" string. These values are used as "parentKey"s by
|
|
1305
|
+
* LiveList children, and define their relative ordering.
|
|
1306
|
+
*/
|
|
1307
|
+
declare type Pos = Brand<string, "Pos">;
|
|
1308
|
+
/**
|
|
1309
|
+
* Given two positions, returns the position value that lies in the middle.
|
|
1310
|
+
* When given only a high bound, computes the canonical position "before" it.
|
|
1311
|
+
* When given only a low bound, computes the canonical position "after" it.
|
|
1312
|
+
* When given no bounds at all, returns the "first" canonical position.
|
|
1313
|
+
*/
|
|
1314
|
+
declare function makePosition(x?: Pos, y?: Pos): Pos;
|
|
1315
|
+
/**
|
|
1316
|
+
* Checks that a str is a valid Pos, and converts it to the nearest valid one
|
|
1317
|
+
* if not.
|
|
1318
|
+
*/
|
|
1319
|
+
declare function asPos(str: string): Pos;
|
|
1320
|
+
|
|
1321
|
+
/**
|
|
1322
|
+
* Shallowly compares two given values.
|
|
1323
|
+
*
|
|
1324
|
+
* - Two simple values are considered equal if they're strictly equal
|
|
1325
|
+
* - Two arrays are considered equal if their members are strictly equal
|
|
1326
|
+
* - Two objects are considered equal if their values are strictly equal
|
|
1327
|
+
*
|
|
1328
|
+
* Testing goes one level deep.
|
|
1329
|
+
*/
|
|
1330
|
+
declare function shallow(a: unknown, b: unknown): boolean;
|
|
1331
|
+
|
|
1266
1332
|
declare type IdTuple<T> = [id: string, value: T];
|
|
1267
1333
|
declare enum CrdtType {
|
|
1268
1334
|
OBJECT = 0,
|
|
@@ -1673,4 +1739,4 @@ declare type EnsureJson<T> = [
|
|
|
1673
1739
|
[K in keyof T]: EnsureJson<T[K]>;
|
|
1674
1740
|
};
|
|
1675
1741
|
|
|
1676
|
-
export { AckOp, AppOnlyAuthToken, AuthToken, BaseUserMeta, BroadcastEventClientMsg, BroadcastOptions, BroadcastedEventServerMsg, Client, ClientMsg, ClientMsgCode, ConnectionStatus, CrdtType, CreateChildOp, CreateListOp, CreateMapOp, CreateObjectOp, CreateOp, CreateRegisterOp, CreateRootObjectOp, DeleteCrdtOp, DeleteObjectKeyOp, DevToolsTreeNode as DevTools, protocol as DevToolsMsg, EnsureJson, FetchStorageClientMsg, History, IdTuple, Immutable, InitialDocumentStateServerMsg, Json, JsonArray, JsonObject, JsonScalar, LiveList, LiveMap, LiveNode, LiveObject, LiveStructure, Lson, LsonObject, NodeMap, Op, OpCode, Others, ParentToChildNodeMap, PlainLson, PlainLsonFields, PlainLsonList, PlainLsonMap, PlainLsonObject, RejectedStorageOpServerMsg, Resolve, Room, RoomAuthToken, RoomInitializers, RoomStateServerMsg, SerializedChild, SerializedCrdt, SerializedList, SerializedMap, SerializedObject, SerializedRegister, SerializedRootObject, ServerMsg, ServerMsgCode, SetParentKeyOp, StorageStatus, StorageUpdate, ToImmutable, ToJson, UpdateObjectOp, UpdatePresenceClientMsg, UpdatePresenceServerMsg, UpdateStorageClientMsg, UpdateStorageServerMsg, User, UserJoinServerMsg, UserLeftServerMsg, WebsocketCloseCodes, asArrayWithLegacyMethods, assert, assertNever, b64decode,
|
|
1742
|
+
export { AckOp, AppOnlyAuthToken, AuthToken, BaseUserMeta, BroadcastEventClientMsg, BroadcastOptions, BroadcastedEventServerMsg, Client, ClientMsg, ClientMsgCode, ConnectionStatus, CrdtType, CreateChildOp, CreateListOp, CreateMapOp, CreateObjectOp, CreateOp, CreateRegisterOp, CreateRootObjectOp, DeleteCrdtOp, DeleteObjectKeyOp, DevToolsTreeNode as DevTools, protocol as DevToolsMsg, EnsureJson, FetchStorageClientMsg, History, IdTuple, Immutable, InitialDocumentStateServerMsg, Json, JsonArray, JsonObject, JsonScalar, LiveList, LiveMap, LiveNode, LiveObject, LiveStructure, Lson, LsonObject, NodeMap, Op, OpCode, Others, ParentToChildNodeMap, PlainLson, PlainLsonFields, PlainLsonList, PlainLsonMap, PlainLsonObject, RejectedStorageOpServerMsg, Resolve, Room, RoomAuthToken, RoomInitializers, RoomStateServerMsg, SerializedChild, SerializedCrdt, SerializedList, SerializedMap, SerializedObject, SerializedRegister, SerializedRootObject, ServerMsg, ServerMsgCode, SetParentKeyOp, StorageStatus, StorageUpdate, ToImmutable, ToJson, UpdateObjectOp, UpdatePresenceClientMsg, UpdatePresenceServerMsg, UpdateStorageClientMsg, UpdateStorageServerMsg, User, UserJoinServerMsg, UserLeftServerMsg, WebsocketCloseCodes, asArrayWithLegacyMethods, asPos, assert, assertNever, b64decode, createClient, deprecate, deprecateIf, errorIf, freeze, isAppOnlyAuthToken, isAuthToken, isChildCrdt, isJsonArray, isJsonObject, isJsonScalar, isPlainObject, isRoomAuthToken, isRootCrdt, legacy_patchImmutableObject, lsonToJson, makePosition, nn, patchLiveObjectKey, shallow, throwUsageError, tryParseJson };
|
package/dist/index.js
CHANGED
|
@@ -117,7 +117,7 @@ var onMessageFromPanel = eventSource.observable;
|
|
|
117
117
|
// src/devtools/index.ts
|
|
118
118
|
var VERSION = true ? (
|
|
119
119
|
/* istanbul ignore next */
|
|
120
|
-
"1.0.
|
|
120
|
+
"1.0.7-test1"
|
|
121
121
|
) : "dev";
|
|
122
122
|
var _devtoolsSetupHasRun = false;
|
|
123
123
|
function setupDevTools(getAllRooms) {
|
|
@@ -345,6 +345,132 @@ function nn(value, errmsg = "Expected value to be non-nullable") {
|
|
|
345
345
|
return value;
|
|
346
346
|
}
|
|
347
347
|
|
|
348
|
+
// src/lib/position.ts
|
|
349
|
+
var MIN_CODE = 32;
|
|
350
|
+
var MAX_CODE = 126;
|
|
351
|
+
var NUM_DIGITS = MAX_CODE - MIN_CODE + 1;
|
|
352
|
+
var ZERO = nthDigit(0);
|
|
353
|
+
var ONE = nthDigit(1);
|
|
354
|
+
var ZERO_NINE = ZERO + nthDigit(-1);
|
|
355
|
+
function nthDigit(n) {
|
|
356
|
+
const code = MIN_CODE + (n < 0 ? NUM_DIGITS + n : n);
|
|
357
|
+
if (code < MIN_CODE || code > MAX_CODE) {
|
|
358
|
+
throw new Error(`Invalid n value: ${n}`);
|
|
359
|
+
}
|
|
360
|
+
return String.fromCharCode(code);
|
|
361
|
+
}
|
|
362
|
+
function makePosition(x, y) {
|
|
363
|
+
if (x !== void 0 && y !== void 0) {
|
|
364
|
+
return between(x, y);
|
|
365
|
+
} else if (x !== void 0) {
|
|
366
|
+
return after(x);
|
|
367
|
+
} else if (y !== void 0) {
|
|
368
|
+
return before(y);
|
|
369
|
+
} else {
|
|
370
|
+
return ONE;
|
|
371
|
+
}
|
|
372
|
+
}
|
|
373
|
+
function before(pos) {
|
|
374
|
+
const lastIndex = pos.length - 1;
|
|
375
|
+
for (let i = 0; i <= lastIndex; i++) {
|
|
376
|
+
const code = pos.charCodeAt(i);
|
|
377
|
+
if (code <= MIN_CODE) {
|
|
378
|
+
continue;
|
|
379
|
+
}
|
|
380
|
+
if (i === lastIndex) {
|
|
381
|
+
if (code === MIN_CODE + 1) {
|
|
382
|
+
return pos.substring(0, i) + ZERO_NINE;
|
|
383
|
+
} else {
|
|
384
|
+
return pos.substring(0, i) + String.fromCharCode(code - 1);
|
|
385
|
+
}
|
|
386
|
+
} else {
|
|
387
|
+
return pos.substring(0, i + 1);
|
|
388
|
+
}
|
|
389
|
+
}
|
|
390
|
+
return ONE;
|
|
391
|
+
}
|
|
392
|
+
function after(pos) {
|
|
393
|
+
for (let i = 0; i <= pos.length - 1; i++) {
|
|
394
|
+
const code = pos.charCodeAt(i);
|
|
395
|
+
if (code >= MAX_CODE) {
|
|
396
|
+
continue;
|
|
397
|
+
}
|
|
398
|
+
return pos.substring(0, i) + String.fromCharCode(code + 1);
|
|
399
|
+
}
|
|
400
|
+
return pos + ONE;
|
|
401
|
+
}
|
|
402
|
+
function between(lo, hi) {
|
|
403
|
+
if (lo < hi) {
|
|
404
|
+
return _between(lo, hi);
|
|
405
|
+
} else if (lo > hi) {
|
|
406
|
+
return _between(hi, lo);
|
|
407
|
+
} else {
|
|
408
|
+
throw new Error("Cannot compute value between two equal positions");
|
|
409
|
+
}
|
|
410
|
+
}
|
|
411
|
+
function _between(lo, hi) {
|
|
412
|
+
let index = 0;
|
|
413
|
+
const loLen = lo.length;
|
|
414
|
+
const hiLen = hi.length;
|
|
415
|
+
while (true) {
|
|
416
|
+
const loCode = index < loLen ? lo.charCodeAt(index) : MIN_CODE;
|
|
417
|
+
const hiCode = index < hiLen ? hi.charCodeAt(index) : MAX_CODE;
|
|
418
|
+
if (loCode === hiCode) {
|
|
419
|
+
index++;
|
|
420
|
+
continue;
|
|
421
|
+
}
|
|
422
|
+
if (hiCode - loCode === 1) {
|
|
423
|
+
const prefix = lo.substring(0, index + 1);
|
|
424
|
+
const suffix = lo.substring(index + 1);
|
|
425
|
+
const nines = "";
|
|
426
|
+
return prefix + _between(suffix, nines);
|
|
427
|
+
} else {
|
|
428
|
+
return takeN(lo, index) + String.fromCharCode(hiCode + loCode >> 1);
|
|
429
|
+
}
|
|
430
|
+
}
|
|
431
|
+
}
|
|
432
|
+
function takeN(pos, n) {
|
|
433
|
+
return n < pos.length ? pos.substring(0, n) : pos + ZERO.repeat(n - pos.length);
|
|
434
|
+
}
|
|
435
|
+
var MIN_NON_ZERO_CODE = MIN_CODE + 1;
|
|
436
|
+
function isPos(str) {
|
|
437
|
+
if (str === "") {
|
|
438
|
+
return false;
|
|
439
|
+
}
|
|
440
|
+
const lastIdx = str.length - 1;
|
|
441
|
+
const last = str.charCodeAt(lastIdx);
|
|
442
|
+
if (last < MIN_NON_ZERO_CODE || last > MAX_CODE) {
|
|
443
|
+
return false;
|
|
444
|
+
}
|
|
445
|
+
for (let i = 0; i < lastIdx; i++) {
|
|
446
|
+
const code = str.charCodeAt(i);
|
|
447
|
+
if (code < MIN_CODE || code > MAX_CODE) {
|
|
448
|
+
return false;
|
|
449
|
+
}
|
|
450
|
+
}
|
|
451
|
+
return true;
|
|
452
|
+
}
|
|
453
|
+
function convertToPos(str) {
|
|
454
|
+
const codes = [];
|
|
455
|
+
for (let i = 0; i < str.length; i++) {
|
|
456
|
+
const code = str.charCodeAt(i);
|
|
457
|
+
codes.push(code < MIN_CODE ? MIN_CODE : code > MAX_CODE ? MAX_CODE : code);
|
|
458
|
+
}
|
|
459
|
+
while (codes.length > 0 && codes[codes.length - 1] === MIN_CODE) {
|
|
460
|
+
codes.length--;
|
|
461
|
+
}
|
|
462
|
+
return codes.length > 0 ? String.fromCharCode(...codes) : (
|
|
463
|
+
// Edge case: the str was a 0-only string, which is invalid. Default back to .1
|
|
464
|
+
ONE
|
|
465
|
+
);
|
|
466
|
+
}
|
|
467
|
+
function asPos(str) {
|
|
468
|
+
return isPos(str) ? str : convertToPos(str);
|
|
469
|
+
}
|
|
470
|
+
function comparePosition(posA, posB) {
|
|
471
|
+
return posA === posB ? 0 : posA < posB ? -1 : 1;
|
|
472
|
+
}
|
|
473
|
+
|
|
348
474
|
// src/protocol/Op.ts
|
|
349
475
|
var OpCode = /* @__PURE__ */ ((OpCode2) => {
|
|
350
476
|
OpCode2[OpCode2["INIT"] = 0] = "INIT";
|
|
@@ -366,12 +492,12 @@ function isAckOp(op) {
|
|
|
366
492
|
function crdtAsLiveNode(value) {
|
|
367
493
|
return value;
|
|
368
494
|
}
|
|
369
|
-
function HasParent(node, key) {
|
|
370
|
-
return Object.freeze({ type: "HasParent", node, key });
|
|
495
|
+
function HasParent(node, key, pos = asPos(key)) {
|
|
496
|
+
return Object.freeze({ type: "HasParent", node, key, pos });
|
|
371
497
|
}
|
|
372
498
|
var NoParent = Object.freeze({ type: "NoParent" });
|
|
373
|
-
function Orphaned(oldKey) {
|
|
374
|
-
return Object.freeze({ type: "Orphaned", oldKey });
|
|
499
|
+
function Orphaned(oldKey, oldPos = asPos(oldKey)) {
|
|
500
|
+
return Object.freeze({ type: "Orphaned", oldKey, oldPos });
|
|
375
501
|
}
|
|
376
502
|
var AbstractCrdt = class {
|
|
377
503
|
constructor() {
|
|
@@ -392,6 +518,19 @@ var AbstractCrdt = class {
|
|
|
392
518
|
}
|
|
393
519
|
}
|
|
394
520
|
/** @internal */
|
|
521
|
+
get _parentPos() {
|
|
522
|
+
switch (this.parent.type) {
|
|
523
|
+
case "HasParent":
|
|
524
|
+
return this.parent.pos;
|
|
525
|
+
case "NoParent":
|
|
526
|
+
throw new Error("Parent key is missing");
|
|
527
|
+
case "Orphaned":
|
|
528
|
+
return this.parent.oldPos;
|
|
529
|
+
default:
|
|
530
|
+
return assertNever(this.parent, "Unknown state");
|
|
531
|
+
}
|
|
532
|
+
}
|
|
533
|
+
/** @internal */
|
|
395
534
|
get _pool() {
|
|
396
535
|
return this.__pool;
|
|
397
536
|
}
|
|
@@ -407,19 +546,6 @@ var AbstractCrdt = class {
|
|
|
407
546
|
return this._parent;
|
|
408
547
|
}
|
|
409
548
|
/** @internal */
|
|
410
|
-
get _parentNode() {
|
|
411
|
-
switch (this.parent.type) {
|
|
412
|
-
case "HasParent":
|
|
413
|
-
return this.parent.node;
|
|
414
|
-
case "NoParent":
|
|
415
|
-
return null;
|
|
416
|
-
case "Orphaned":
|
|
417
|
-
return null;
|
|
418
|
-
default:
|
|
419
|
-
return assertNever(this.parent, "Unknown state");
|
|
420
|
-
}
|
|
421
|
-
}
|
|
422
|
-
/** @internal */
|
|
423
549
|
get _parentKey() {
|
|
424
550
|
switch (this.parent.type) {
|
|
425
551
|
case "HasParent":
|
|
@@ -479,7 +605,7 @@ var AbstractCrdt = class {
|
|
|
479
605
|
}
|
|
480
606
|
switch (this.parent.type) {
|
|
481
607
|
case "HasParent": {
|
|
482
|
-
this._parent = Orphaned(this.parent.key);
|
|
608
|
+
this._parent = Orphaned(this.parent.key, this.parent.pos);
|
|
483
609
|
break;
|
|
484
610
|
}
|
|
485
611
|
case "NoParent": {
|
|
@@ -487,7 +613,6 @@ var AbstractCrdt = class {
|
|
|
487
613
|
break;
|
|
488
614
|
}
|
|
489
615
|
case "Orphaned": {
|
|
490
|
-
this._parent = Orphaned(this.parent.oldKey);
|
|
491
616
|
break;
|
|
492
617
|
}
|
|
493
618
|
default:
|
|
@@ -609,110 +734,6 @@ function nanoid(length = 7) {
|
|
|
609
734
|
).join("");
|
|
610
735
|
}
|
|
611
736
|
|
|
612
|
-
// src/lib/position.ts
|
|
613
|
-
var min = 32;
|
|
614
|
-
var max = 126;
|
|
615
|
-
function makePosition(before, after) {
|
|
616
|
-
if (before !== void 0 && after !== void 0) {
|
|
617
|
-
return pos(makePositionFromCodes(posCodes(before), posCodes(after)));
|
|
618
|
-
} else if (before !== void 0) {
|
|
619
|
-
return getNextPosition(before);
|
|
620
|
-
} else if (after !== void 0) {
|
|
621
|
-
return getPreviousPosition(after);
|
|
622
|
-
}
|
|
623
|
-
return pos([min + 1]);
|
|
624
|
-
}
|
|
625
|
-
function getPreviousPosition(after) {
|
|
626
|
-
const result = [];
|
|
627
|
-
const afterCodes = posCodes(after);
|
|
628
|
-
for (let i = 0; i < afterCodes.length; i++) {
|
|
629
|
-
const code = afterCodes[i];
|
|
630
|
-
if (code <= min + 1) {
|
|
631
|
-
result.push(min);
|
|
632
|
-
if (afterCodes.length - 1 === i) {
|
|
633
|
-
result.push(max);
|
|
634
|
-
break;
|
|
635
|
-
}
|
|
636
|
-
} else {
|
|
637
|
-
result.push(code - 1);
|
|
638
|
-
break;
|
|
639
|
-
}
|
|
640
|
-
}
|
|
641
|
-
return pos(result);
|
|
642
|
-
}
|
|
643
|
-
function getNextPosition(before) {
|
|
644
|
-
const result = [];
|
|
645
|
-
const beforeCodes = posCodes(before);
|
|
646
|
-
for (let i = 0; i < beforeCodes.length; i++) {
|
|
647
|
-
const code = beforeCodes[i];
|
|
648
|
-
if (code === max) {
|
|
649
|
-
result.push(code);
|
|
650
|
-
if (beforeCodes.length - 1 === i) {
|
|
651
|
-
result.push(min + 1);
|
|
652
|
-
break;
|
|
653
|
-
}
|
|
654
|
-
} else {
|
|
655
|
-
result.push(code + 1);
|
|
656
|
-
break;
|
|
657
|
-
}
|
|
658
|
-
}
|
|
659
|
-
return pos(result);
|
|
660
|
-
}
|
|
661
|
-
function makePositionFromCodes(before, after) {
|
|
662
|
-
let index = 0;
|
|
663
|
-
const result = [];
|
|
664
|
-
while (true) {
|
|
665
|
-
const beforeDigit = before[index] || min;
|
|
666
|
-
const afterDigit = after[index] || max;
|
|
667
|
-
if (beforeDigit > afterDigit) {
|
|
668
|
-
throw new Error(
|
|
669
|
-
`Impossible to generate position between ${before} and ${after}`
|
|
670
|
-
);
|
|
671
|
-
}
|
|
672
|
-
if (beforeDigit === afterDigit) {
|
|
673
|
-
result.push(beforeDigit);
|
|
674
|
-
index++;
|
|
675
|
-
continue;
|
|
676
|
-
}
|
|
677
|
-
if (afterDigit - beforeDigit === 1) {
|
|
678
|
-
result.push(beforeDigit);
|
|
679
|
-
result.push(...makePositionFromCodes(before.slice(index + 1), []));
|
|
680
|
-
break;
|
|
681
|
-
}
|
|
682
|
-
const mid = afterDigit + beforeDigit >> 1;
|
|
683
|
-
result.push(mid);
|
|
684
|
-
break;
|
|
685
|
-
}
|
|
686
|
-
return result;
|
|
687
|
-
}
|
|
688
|
-
function posCodes(str) {
|
|
689
|
-
const codes = [];
|
|
690
|
-
for (let i = 0; i < str.length; i++) {
|
|
691
|
-
codes.push(str.charCodeAt(i));
|
|
692
|
-
}
|
|
693
|
-
return codes;
|
|
694
|
-
}
|
|
695
|
-
function pos(codes) {
|
|
696
|
-
return String.fromCharCode(...codes);
|
|
697
|
-
}
|
|
698
|
-
function comparePosition(posA, posB) {
|
|
699
|
-
const aCodes = posCodes(posA);
|
|
700
|
-
const bCodes = posCodes(posB);
|
|
701
|
-
const maxLength = Math.max(aCodes.length, bCodes.length);
|
|
702
|
-
for (let i = 0; i < maxLength; i++) {
|
|
703
|
-
const a = aCodes[i] === void 0 ? min : aCodes[i];
|
|
704
|
-
const b = bCodes[i] === void 0 ? min : bCodes[i];
|
|
705
|
-
if (a === b) {
|
|
706
|
-
continue;
|
|
707
|
-
} else {
|
|
708
|
-
return a - b;
|
|
709
|
-
}
|
|
710
|
-
}
|
|
711
|
-
throw new Error(
|
|
712
|
-
`Impossible to compare similar position "${posA}" and "${posB}"`
|
|
713
|
-
);
|
|
714
|
-
}
|
|
715
|
-
|
|
716
737
|
// src/crdts/LiveRegister.ts
|
|
717
738
|
var LiveRegister = class extends AbstractCrdt {
|
|
718
739
|
constructor(data) {
|
|
@@ -788,10 +809,7 @@ var LiveRegister = class extends AbstractCrdt {
|
|
|
788
809
|
|
|
789
810
|
// src/crdts/LiveList.ts
|
|
790
811
|
function compareNodePosition(itemA, itemB) {
|
|
791
|
-
return comparePosition(
|
|
792
|
-
itemA._getParentKeyOrThrow(),
|
|
793
|
-
itemB._getParentKeyOrThrow()
|
|
794
|
-
);
|
|
812
|
+
return comparePosition(itemA._parentPos, itemB._parentPos);
|
|
795
813
|
}
|
|
796
814
|
var LiveList = class extends AbstractCrdt {
|
|
797
815
|
constructor(items = []) {
|
|
@@ -1033,7 +1051,7 @@ var LiveList = class extends AbstractCrdt {
|
|
|
1033
1051
|
if (this._pool === void 0) {
|
|
1034
1052
|
throw new Error("Can't attach child if managed pool is not present");
|
|
1035
1053
|
}
|
|
1036
|
-
const key = op.parentKey;
|
|
1054
|
+
const key = asPos(op.parentKey);
|
|
1037
1055
|
const existingItemIndex = this._indexOfPosition(key);
|
|
1038
1056
|
if (existingItemIndex !== -1) {
|
|
1039
1057
|
this._shiftItemPosition(existingItemIndex, key);
|
|
@@ -1047,7 +1065,7 @@ var LiveList = class extends AbstractCrdt {
|
|
|
1047
1065
|
/** @internal */
|
|
1048
1066
|
_applyInsertAck(op) {
|
|
1049
1067
|
const existingItem = this._items.find((item) => item._id === op.id);
|
|
1050
|
-
const key = op.parentKey;
|
|
1068
|
+
const key = asPos(op.parentKey);
|
|
1051
1069
|
const itemIndexAtPosition = this._indexOfPosition(key);
|
|
1052
1070
|
if (existingItem) {
|
|
1053
1071
|
if (existingItem._parentKey === key) {
|
|
@@ -1108,9 +1126,9 @@ var LiveList = class extends AbstractCrdt {
|
|
|
1108
1126
|
const existingItemIndex = this._indexOfPosition(key);
|
|
1109
1127
|
let newKey = key;
|
|
1110
1128
|
if (existingItemIndex !== -1) {
|
|
1111
|
-
const
|
|
1112
|
-
const
|
|
1113
|
-
newKey = makePosition(
|
|
1129
|
+
const before2 = (_b = this._items[existingItemIndex]) == null ? void 0 : _b._parentPos;
|
|
1130
|
+
const after2 = (_c = this._items[existingItemIndex + 1]) == null ? void 0 : _c._parentPos;
|
|
1131
|
+
newKey = makePosition(before2, after2);
|
|
1114
1132
|
child._setParentLink(this, newKey);
|
|
1115
1133
|
}
|
|
1116
1134
|
this._insertAndSort(child);
|
|
@@ -1248,10 +1266,7 @@ var LiveList = class extends AbstractCrdt {
|
|
|
1248
1266
|
} else {
|
|
1249
1267
|
this._items[existingItemIndex]._setParentLink(
|
|
1250
1268
|
this,
|
|
1251
|
-
makePosition(
|
|
1252
|
-
newKey,
|
|
1253
|
-
(_a = this._items[existingItemIndex + 1]) == null ? void 0 : _a._getParentKeyOrThrow()
|
|
1254
|
-
)
|
|
1269
|
+
makePosition(newKey, (_a = this._items[existingItemIndex + 1]) == null ? void 0 : _a._parentPos)
|
|
1255
1270
|
);
|
|
1256
1271
|
const previousIndex = this._items.indexOf(child);
|
|
1257
1272
|
child._setParentLink(this, newKey);
|
|
@@ -1278,10 +1293,7 @@ var LiveList = class extends AbstractCrdt {
|
|
|
1278
1293
|
if (existingItemIndex !== -1) {
|
|
1279
1294
|
this._items[existingItemIndex]._setParentLink(
|
|
1280
1295
|
this,
|
|
1281
|
-
makePosition(
|
|
1282
|
-
newKey,
|
|
1283
|
-
(_a = this._items[existingItemIndex + 1]) == null ? void 0 : _a._getParentKeyOrThrow()
|
|
1284
|
-
)
|
|
1296
|
+
makePosition(newKey, (_a = this._items[existingItemIndex + 1]) == null ? void 0 : _a._parentPos)
|
|
1285
1297
|
);
|
|
1286
1298
|
}
|
|
1287
1299
|
child._setParentLink(this, newKey);
|
|
@@ -1300,10 +1312,7 @@ var LiveList = class extends AbstractCrdt {
|
|
|
1300
1312
|
if (existingItemIndex !== -1) {
|
|
1301
1313
|
this._items[existingItemIndex]._setParentLink(
|
|
1302
1314
|
this,
|
|
1303
|
-
makePosition(
|
|
1304
|
-
newKey,
|
|
1305
|
-
(_b = this._items[existingItemIndex + 1]) == null ? void 0 : _b._getParentKeyOrThrow()
|
|
1306
|
-
)
|
|
1315
|
+
makePosition(newKey, (_b = this._items[existingItemIndex + 1]) == null ? void 0 : _b._parentPos)
|
|
1307
1316
|
);
|
|
1308
1317
|
}
|
|
1309
1318
|
child._setParentLink(this, newKey);
|
|
@@ -1332,10 +1341,7 @@ var LiveList = class extends AbstractCrdt {
|
|
|
1332
1341
|
if (existingItemIndex !== -1) {
|
|
1333
1342
|
this._items[existingItemIndex]._setParentLink(
|
|
1334
1343
|
this,
|
|
1335
|
-
makePosition(
|
|
1336
|
-
newKey,
|
|
1337
|
-
(_a = this._items[existingItemIndex + 1]) == null ? void 0 : _a._getParentKeyOrThrow()
|
|
1338
|
-
)
|
|
1344
|
+
makePosition(newKey, (_a = this._items[existingItemIndex + 1]) == null ? void 0 : _a._parentPos)
|
|
1339
1345
|
);
|
|
1340
1346
|
}
|
|
1341
1347
|
child._setParentLink(this, newKey);
|
|
@@ -1410,9 +1416,9 @@ var LiveList = class extends AbstractCrdt {
|
|
|
1410
1416
|
`Cannot insert list item at index "${index}". index should be between 0 and ${this._items.length}`
|
|
1411
1417
|
);
|
|
1412
1418
|
}
|
|
1413
|
-
const
|
|
1414
|
-
const
|
|
1415
|
-
const position = makePosition(
|
|
1419
|
+
const before2 = this._items[index - 1] ? this._items[index - 1]._parentPos : void 0;
|
|
1420
|
+
const after2 = this._items[index] ? this._items[index]._parentPos : void 0;
|
|
1421
|
+
const position = makePosition(before2, after2);
|
|
1416
1422
|
const value = lsonToLiveNode(element);
|
|
1417
1423
|
value._setParentLink(this, position);
|
|
1418
1424
|
this._insertAndSort(value);
|
|
@@ -1453,11 +1459,11 @@ var LiveList = class extends AbstractCrdt {
|
|
|
1453
1459
|
let beforePosition = null;
|
|
1454
1460
|
let afterPosition = null;
|
|
1455
1461
|
if (index < targetIndex) {
|
|
1456
|
-
afterPosition = targetIndex === this._items.length - 1 ? void 0 : this._items[targetIndex + 1].
|
|
1457
|
-
beforePosition = this._items[targetIndex].
|
|
1462
|
+
afterPosition = targetIndex === this._items.length - 1 ? void 0 : this._items[targetIndex + 1]._parentPos;
|
|
1463
|
+
beforePosition = this._items[targetIndex]._parentPos;
|
|
1458
1464
|
} else {
|
|
1459
|
-
afterPosition = this._items[targetIndex].
|
|
1460
|
-
beforePosition = targetIndex === 0 ? void 0 : this._items[targetIndex - 1].
|
|
1465
|
+
afterPosition = this._items[targetIndex]._parentPos;
|
|
1466
|
+
beforePosition = targetIndex === 0 ? void 0 : this._items[targetIndex - 1]._parentPos;
|
|
1461
1467
|
}
|
|
1462
1468
|
const position = makePosition(beforePosition, afterPosition);
|
|
1463
1469
|
const item = this._items[index];
|
|
@@ -1712,7 +1718,7 @@ var LiveList = class extends AbstractCrdt {
|
|
|
1712
1718
|
var _a;
|
|
1713
1719
|
const shiftedPosition = makePosition(
|
|
1714
1720
|
key,
|
|
1715
|
-
this._items.length > index + 1 ? (_a = this._items[index + 1]) == null ? void 0 : _a.
|
|
1721
|
+
this._items.length > index + 1 ? (_a = this._items[index + 1]) == null ? void 0 : _a._parentPos : void 0
|
|
1716
1722
|
);
|
|
1717
1723
|
this._items[index]._setParentLink(this, shiftedPosition);
|
|
1718
1724
|
}
|
|
@@ -2173,6 +2179,37 @@ var LiveObject = class extends AbstractCrdt {
|
|
|
2173
2179
|
this._map = new Map(Object.entries(obj));
|
|
2174
2180
|
}
|
|
2175
2181
|
/** @internal */
|
|
2182
|
+
static _buildRootAndParentToChildren(items) {
|
|
2183
|
+
const parentToChildren = /* @__PURE__ */ new Map();
|
|
2184
|
+
let root = null;
|
|
2185
|
+
for (const [id, crdt] of items) {
|
|
2186
|
+
if (isRootCrdt(crdt)) {
|
|
2187
|
+
root = [id, crdt];
|
|
2188
|
+
} else {
|
|
2189
|
+
const tuple = [id, crdt];
|
|
2190
|
+
const children = parentToChildren.get(crdt.parentId);
|
|
2191
|
+
if (children !== void 0) {
|
|
2192
|
+
children.push(tuple);
|
|
2193
|
+
} else {
|
|
2194
|
+
parentToChildren.set(crdt.parentId, [tuple]);
|
|
2195
|
+
}
|
|
2196
|
+
}
|
|
2197
|
+
}
|
|
2198
|
+
if (root === null) {
|
|
2199
|
+
throw new Error("Root can't be null");
|
|
2200
|
+
}
|
|
2201
|
+
return [root, parentToChildren];
|
|
2202
|
+
}
|
|
2203
|
+
/** @internal */
|
|
2204
|
+
static _fromItems(items, pool) {
|
|
2205
|
+
const [root, parentToChildren] = LiveObject._buildRootAndParentToChildren(items);
|
|
2206
|
+
return LiveObject._deserialize(
|
|
2207
|
+
root,
|
|
2208
|
+
parentToChildren,
|
|
2209
|
+
pool
|
|
2210
|
+
);
|
|
2211
|
+
}
|
|
2212
|
+
/** @internal */
|
|
2176
2213
|
_toOps(parentId, parentKey, pool) {
|
|
2177
2214
|
if (this._id === void 0) {
|
|
2178
2215
|
throw new Error("Cannot serialize item is not attached");
|
|
@@ -3243,14 +3280,15 @@ function makeStateMachine(config, initialPresence, initialStorage) {
|
|
|
3243
3280
|
token: null,
|
|
3244
3281
|
lastConnectionId: null,
|
|
3245
3282
|
socket: null,
|
|
3246
|
-
|
|
3247
|
-
|
|
3248
|
-
timeoutHandles: {
|
|
3283
|
+
numRetries: 0,
|
|
3284
|
+
timers: {
|
|
3249
3285
|
flush: void 0,
|
|
3250
3286
|
reconnect: void 0,
|
|
3287
|
+
heartbeat: void 0,
|
|
3251
3288
|
pongTimeout: void 0
|
|
3252
3289
|
},
|
|
3253
3290
|
buffer: {
|
|
3291
|
+
lastFlushedAt: 0,
|
|
3254
3292
|
me: (
|
|
3255
3293
|
// Queue up the initial presence message as a Full Presence™ update
|
|
3256
3294
|
{
|
|
@@ -3261,9 +3299,6 @@ function makeStateMachine(config, initialPresence, initialStorage) {
|
|
|
3261
3299
|
messages: [],
|
|
3262
3300
|
storageOperations: []
|
|
3263
3301
|
},
|
|
3264
|
-
intervalHandles: {
|
|
3265
|
-
heartbeat: void 0
|
|
3266
|
-
},
|
|
3267
3302
|
connection: new ValueRef({ status: "closed" }),
|
|
3268
3303
|
me: new MeRef(initialPresence),
|
|
3269
3304
|
others: new OthersRef(),
|
|
@@ -3296,16 +3331,16 @@ function makeStateMachine(config, initialPresence, initialStorage) {
|
|
|
3296
3331
|
if (process.env.NODE_ENV !== "production") {
|
|
3297
3332
|
const stackTrace = captureStackTrace("Storage mutation", this.dispatch);
|
|
3298
3333
|
if (stackTrace) {
|
|
3299
|
-
|
|
3334
|
+
for (const op of ops) {
|
|
3300
3335
|
if (op.opId) {
|
|
3301
3336
|
nn(context.opStackTraces).set(op.opId, stackTrace);
|
|
3302
3337
|
}
|
|
3303
|
-
}
|
|
3338
|
+
}
|
|
3304
3339
|
}
|
|
3305
3340
|
}
|
|
3306
3341
|
if (activeBatch) {
|
|
3307
3342
|
activeBatch.ops.push(...ops);
|
|
3308
|
-
|
|
3343
|
+
for (const [key, value] of storageUpdates) {
|
|
3309
3344
|
activeBatch.updates.storageUpdates.set(
|
|
3310
3345
|
key,
|
|
3311
3346
|
mergeStorageUpdates(
|
|
@@ -3313,7 +3348,7 @@ function makeStateMachine(config, initialPresence, initialStorage) {
|
|
|
3313
3348
|
value
|
|
3314
3349
|
)
|
|
3315
3350
|
);
|
|
3316
|
-
}
|
|
3351
|
+
}
|
|
3317
3352
|
activeBatch.reverseOps.unshift(...reverse);
|
|
3318
3353
|
} else {
|
|
3319
3354
|
batchUpdates(() => {
|
|
@@ -3372,18 +3407,10 @@ function makeStateMachine(config, initialPresence, initialStorage) {
|
|
|
3372
3407
|
}
|
|
3373
3408
|
context.socket.send(JSON.stringify(messageOrMessages));
|
|
3374
3409
|
},
|
|
3375
|
-
|
|
3376
|
-
|
|
3377
|
-
|
|
3378
|
-
|
|
3379
|
-
return setInterval(heartbeat, HEARTBEAT_INTERVAL);
|
|
3380
|
-
},
|
|
3381
|
-
schedulePongTimeout() {
|
|
3382
|
-
return setTimeout(pongTimeout, PONG_TIMEOUT);
|
|
3383
|
-
},
|
|
3384
|
-
scheduleReconnect(delay) {
|
|
3385
|
-
return setTimeout(connect, delay);
|
|
3386
|
-
}
|
|
3410
|
+
scheduleFlush: (delay) => setTimeout(tryFlushing, delay),
|
|
3411
|
+
scheduleReconnect: (delay) => setTimeout(connect, delay),
|
|
3412
|
+
startHeartbeatInterval: () => setInterval(heartbeat, HEARTBEAT_INTERVAL),
|
|
3413
|
+
schedulePongTimeout: () => setTimeout(pongTimeout, PONG_TIMEOUT)
|
|
3387
3414
|
};
|
|
3388
3415
|
const self = new DerivedRef(
|
|
3389
3416
|
context.connection,
|
|
@@ -3407,7 +3434,7 @@ function makeStateMachine(config, initialPresence, initialStorage) {
|
|
|
3407
3434
|
if (context.root) {
|
|
3408
3435
|
updateRoot(message.items, batchedUpdatesWrapper);
|
|
3409
3436
|
} else {
|
|
3410
|
-
context.root =
|
|
3437
|
+
context.root = LiveObject._fromItems(message.items, pool);
|
|
3411
3438
|
}
|
|
3412
3439
|
for (const key in context.initialStorage) {
|
|
3413
3440
|
if (context.root.get(key) === void 0) {
|
|
@@ -3415,43 +3442,18 @@ function makeStateMachine(config, initialPresence, initialStorage) {
|
|
|
3415
3442
|
}
|
|
3416
3443
|
}
|
|
3417
3444
|
}
|
|
3418
|
-
function buildRootAndParentToChildren(items) {
|
|
3419
|
-
const parentToChildren = /* @__PURE__ */ new Map();
|
|
3420
|
-
let root = null;
|
|
3421
|
-
for (const [id, crdt] of items) {
|
|
3422
|
-
if (isRootCrdt(crdt)) {
|
|
3423
|
-
root = [id, crdt];
|
|
3424
|
-
} else {
|
|
3425
|
-
const tuple = [id, crdt];
|
|
3426
|
-
const children = parentToChildren.get(crdt.parentId);
|
|
3427
|
-
if (children !== void 0) {
|
|
3428
|
-
children.push(tuple);
|
|
3429
|
-
} else {
|
|
3430
|
-
parentToChildren.set(crdt.parentId, [tuple]);
|
|
3431
|
-
}
|
|
3432
|
-
}
|
|
3433
|
-
}
|
|
3434
|
-
if (root === null) {
|
|
3435
|
-
throw new Error("Root can't be null");
|
|
3436
|
-
}
|
|
3437
|
-
return [root, parentToChildren];
|
|
3438
|
-
}
|
|
3439
3445
|
function updateRoot(items, batchedUpdatesWrapper) {
|
|
3440
3446
|
if (!context.root) {
|
|
3441
3447
|
return;
|
|
3442
3448
|
}
|
|
3443
3449
|
const currentItems = /* @__PURE__ */ new Map();
|
|
3444
|
-
context.nodes
|
|
3450
|
+
for (const [id, node] of context.nodes) {
|
|
3445
3451
|
currentItems.set(id, node._serialize());
|
|
3446
|
-
}
|
|
3452
|
+
}
|
|
3447
3453
|
const ops = getTreesDiffOperations(currentItems, new Map(items));
|
|
3448
3454
|
const result = applyOps(ops, false);
|
|
3449
3455
|
notify(result.updates, batchedUpdatesWrapper);
|
|
3450
3456
|
}
|
|
3451
|
-
function load(items) {
|
|
3452
|
-
const [root, parentToChildren] = buildRootAndParentToChildren(items);
|
|
3453
|
-
return LiveObject._deserialize(root, parentToChildren, pool);
|
|
3454
|
-
}
|
|
3455
3457
|
function _addToRealUndoStack(historyOps, batchedUpdatesWrapper) {
|
|
3456
3458
|
if (context.undoStack.length >= 50) {
|
|
3457
3459
|
context.undoStack.shift();
|
|
@@ -3592,7 +3594,11 @@ function makeStateMachine(config, initialPresence, initialStorage) {
|
|
|
3592
3594
|
return { modified: false };
|
|
3593
3595
|
}
|
|
3594
3596
|
if (node.parent.type === "HasParent" && isLiveList(node.parent.node)) {
|
|
3595
|
-
return node.parent.node._setChildKey(
|
|
3597
|
+
return node.parent.node._setChildKey(
|
|
3598
|
+
asPos(op.parentKey),
|
|
3599
|
+
node,
|
|
3600
|
+
source
|
|
3601
|
+
);
|
|
3596
3602
|
}
|
|
3597
3603
|
return { modified: false };
|
|
3598
3604
|
}
|
|
@@ -3692,10 +3698,9 @@ function makeStateMachine(config, initialPresence, initialStorage) {
|
|
|
3692
3698
|
}
|
|
3693
3699
|
context.token = null;
|
|
3694
3700
|
updateConnection({ status: "unavailable" }, batchUpdates);
|
|
3695
|
-
context.
|
|
3696
|
-
context.
|
|
3697
|
-
|
|
3698
|
-
);
|
|
3701
|
+
context.numRetries++;
|
|
3702
|
+
clearTimeout(context.timers.reconnect);
|
|
3703
|
+
context.timers.reconnect = effects.scheduleReconnect(getRetryDelay());
|
|
3699
3704
|
}
|
|
3700
3705
|
function onVisibilityChange(visibilityState) {
|
|
3701
3706
|
if (visibilityState === "visible" && context.connection.current.status === "open") {
|
|
@@ -3758,6 +3763,12 @@ function makeStateMachine(config, initialPresence, initialStorage) {
|
|
|
3758
3763
|
reconnect();
|
|
3759
3764
|
}
|
|
3760
3765
|
}
|
|
3766
|
+
function canUndo() {
|
|
3767
|
+
return context.undoStack.length > 0;
|
|
3768
|
+
}
|
|
3769
|
+
function canRedo() {
|
|
3770
|
+
return context.redoStack.length > 0;
|
|
3771
|
+
}
|
|
3761
3772
|
function onHistoryChange(batchedUpdatesWrapper) {
|
|
3762
3773
|
batchedUpdatesWrapper(() => {
|
|
3763
3774
|
eventHub.history.notify({ canUndo: canUndo(), canRedo: canRedo() });
|
|
@@ -3795,9 +3806,23 @@ function makeStateMachine(config, initialPresence, initialStorage) {
|
|
|
3795
3806
|
return compact([parseServerMessage(data)]);
|
|
3796
3807
|
}
|
|
3797
3808
|
}
|
|
3809
|
+
function applyAndSendOps(offlineOps, batchedUpdatesWrapper) {
|
|
3810
|
+
if (offlineOps.size === 0) {
|
|
3811
|
+
return;
|
|
3812
|
+
}
|
|
3813
|
+
const messages = [];
|
|
3814
|
+
const ops = Array.from(offlineOps.values());
|
|
3815
|
+
const result = applyOps(ops, true);
|
|
3816
|
+
messages.push({
|
|
3817
|
+
type: 201 /* UPDATE_STORAGE */,
|
|
3818
|
+
ops: result.ops
|
|
3819
|
+
});
|
|
3820
|
+
notify(result.updates, batchedUpdatesWrapper);
|
|
3821
|
+
effects.send(messages);
|
|
3822
|
+
}
|
|
3798
3823
|
function onMessage(event) {
|
|
3799
3824
|
if (event.data === "pong") {
|
|
3800
|
-
clearTimeout(context.
|
|
3825
|
+
clearTimeout(context.timers.pongTimeout);
|
|
3801
3826
|
return;
|
|
3802
3827
|
}
|
|
3803
3828
|
const messages = parseServerMessages(event.data);
|
|
@@ -3857,12 +3882,12 @@ function makeStateMachine(config, initialPresence, initialStorage) {
|
|
|
3857
3882
|
}
|
|
3858
3883
|
case 201 /* UPDATE_STORAGE */: {
|
|
3859
3884
|
const applyResult = applyOps(message.ops, false);
|
|
3860
|
-
applyResult.updates.storageUpdates
|
|
3885
|
+
for (const [key, value] of applyResult.updates.storageUpdates) {
|
|
3861
3886
|
updates.storageUpdates.set(
|
|
3862
3887
|
key,
|
|
3863
3888
|
mergeStorageUpdates(updates.storageUpdates.get(key), value)
|
|
3864
3889
|
);
|
|
3865
|
-
}
|
|
3890
|
+
}
|
|
3866
3891
|
break;
|
|
3867
3892
|
}
|
|
3868
3893
|
case 299 /* REJECT_STORAGE_OP */: {
|
|
@@ -3899,12 +3924,10 @@ ${Array.from(traces).join("\n\n")}`
|
|
|
3899
3924
|
}
|
|
3900
3925
|
function onClose(event) {
|
|
3901
3926
|
context.socket = null;
|
|
3902
|
-
clearTimeout(context.
|
|
3903
|
-
|
|
3904
|
-
|
|
3905
|
-
|
|
3906
|
-
}
|
|
3907
|
-
clearTimeout(context.timeoutHandles.reconnect);
|
|
3927
|
+
clearTimeout(context.timers.flush);
|
|
3928
|
+
clearTimeout(context.timers.reconnect);
|
|
3929
|
+
clearInterval(context.timers.heartbeat);
|
|
3930
|
+
clearTimeout(context.timers.pongTimeout);
|
|
3908
3931
|
context.others.clearOthers();
|
|
3909
3932
|
batchUpdates(() => {
|
|
3910
3933
|
notify({ others: [{ type: "reset" }] }, doNotBatchUpdates);
|
|
@@ -3913,26 +3936,28 @@ ${Array.from(traces).join("\n\n")}`
|
|
|
3913
3936
|
const error2 = new LiveblocksError(event.reason, event.code);
|
|
3914
3937
|
eventHub.error.notify(error2);
|
|
3915
3938
|
const delay = getRetryDelay(true);
|
|
3916
|
-
context.
|
|
3939
|
+
context.numRetries++;
|
|
3917
3940
|
if (process.env.NODE_ENV !== "production") {
|
|
3918
3941
|
error(
|
|
3919
3942
|
`Connection to websocket server closed. Reason: ${error2.message} (code: ${error2.code}). Retrying in ${delay}ms.`
|
|
3920
3943
|
);
|
|
3921
3944
|
}
|
|
3922
3945
|
updateConnection({ status: "unavailable" }, doNotBatchUpdates);
|
|
3923
|
-
context.
|
|
3946
|
+
clearTimeout(context.timers.reconnect);
|
|
3947
|
+
context.timers.reconnect = effects.scheduleReconnect(delay);
|
|
3924
3948
|
} else if (event.code === 4999 /* CLOSE_WITHOUT_RETRY */) {
|
|
3925
3949
|
updateConnection({ status: "closed" }, doNotBatchUpdates);
|
|
3926
3950
|
} else {
|
|
3927
3951
|
const delay = getRetryDelay();
|
|
3928
|
-
context.
|
|
3952
|
+
context.numRetries++;
|
|
3929
3953
|
if (process.env.NODE_ENV !== "production") {
|
|
3930
3954
|
warn(
|
|
3931
3955
|
`Connection to Liveblocks websocket server closed (code: ${event.code}). Retrying in ${delay}ms.`
|
|
3932
3956
|
);
|
|
3933
3957
|
}
|
|
3934
3958
|
updateConnection({ status: "unavailable" }, doNotBatchUpdates);
|
|
3935
|
-
context.
|
|
3959
|
+
clearTimeout(context.timers.reconnect);
|
|
3960
|
+
context.timers.reconnect = effects.scheduleReconnect(delay);
|
|
3936
3961
|
}
|
|
3937
3962
|
});
|
|
3938
3963
|
}
|
|
@@ -3944,21 +3969,21 @@ ${Array.from(traces).join("\n\n")}`
|
|
|
3944
3969
|
}
|
|
3945
3970
|
function getRetryDelay(slow = false) {
|
|
3946
3971
|
if (slow) {
|
|
3947
|
-
return BACKOFF_RETRY_DELAYS_SLOW[context.
|
|
3972
|
+
return BACKOFF_RETRY_DELAYS_SLOW[context.numRetries < BACKOFF_RETRY_DELAYS_SLOW.length ? context.numRetries : BACKOFF_RETRY_DELAYS_SLOW.length - 1];
|
|
3948
3973
|
}
|
|
3949
|
-
return BACKOFF_RETRY_DELAYS[context.
|
|
3974
|
+
return BACKOFF_RETRY_DELAYS[context.numRetries < BACKOFF_RETRY_DELAYS.length ? context.numRetries : BACKOFF_RETRY_DELAYS.length - 1];
|
|
3950
3975
|
}
|
|
3951
3976
|
function onError() {
|
|
3952
3977
|
}
|
|
3953
3978
|
function onOpen() {
|
|
3954
|
-
clearInterval(context.
|
|
3955
|
-
context.
|
|
3979
|
+
clearInterval(context.timers.heartbeat);
|
|
3980
|
+
context.timers.heartbeat = effects.startHeartbeatInterval();
|
|
3956
3981
|
if (context.connection.current.status === "connecting") {
|
|
3957
3982
|
updateConnection(
|
|
3958
3983
|
__spreadProps(__spreadValues({}, context.connection.current), { status: "open" }),
|
|
3959
3984
|
batchUpdates
|
|
3960
3985
|
);
|
|
3961
|
-
context.
|
|
3986
|
+
context.numRetries = 0;
|
|
3962
3987
|
if (context.lastConnectionId !== void 0) {
|
|
3963
3988
|
context.buffer.me = {
|
|
3964
3989
|
type: "full",
|
|
@@ -3983,8 +4008,8 @@ ${Array.from(traces).join("\n\n")}`
|
|
|
3983
4008
|
if (context.socket === null) {
|
|
3984
4009
|
return;
|
|
3985
4010
|
}
|
|
3986
|
-
clearTimeout(context.
|
|
3987
|
-
context.
|
|
4011
|
+
clearTimeout(context.timers.pongTimeout);
|
|
4012
|
+
context.timers.pongTimeout = effects.schedulePongTimeout();
|
|
3988
4013
|
if (context.socket.readyState === context.socket.OPEN) {
|
|
3989
4014
|
context.socket.send("ping");
|
|
3990
4015
|
}
|
|
@@ -3993,7 +4018,7 @@ ${Array.from(traces).join("\n\n")}`
|
|
|
3993
4018
|
log("Pong timeout. Trying to reconnect.");
|
|
3994
4019
|
reconnect();
|
|
3995
4020
|
}
|
|
3996
|
-
function
|
|
4021
|
+
function disconnect() {
|
|
3997
4022
|
if (context.socket) {
|
|
3998
4023
|
context.socket.removeEventListener("open", onOpen);
|
|
3999
4024
|
context.socket.removeEventListener("message", onMessage);
|
|
@@ -4002,35 +4027,41 @@ ${Array.from(traces).join("\n\n")}`
|
|
|
4002
4027
|
context.socket.close();
|
|
4003
4028
|
context.socket = null;
|
|
4004
4029
|
}
|
|
4005
|
-
|
|
4006
|
-
clearTimeout(context.
|
|
4007
|
-
|
|
4008
|
-
|
|
4030
|
+
clearTimeout(context.timers.flush);
|
|
4031
|
+
clearTimeout(context.timers.reconnect);
|
|
4032
|
+
clearInterval(context.timers.heartbeat);
|
|
4033
|
+
clearTimeout(context.timers.pongTimeout);
|
|
4034
|
+
batchUpdates(() => {
|
|
4035
|
+
updateConnection({ status: "closed" }, doNotBatchUpdates);
|
|
4036
|
+
context.others.clearOthers();
|
|
4037
|
+
notify({ others: [{ type: "reset" }] }, doNotBatchUpdates);
|
|
4038
|
+
});
|
|
4039
|
+
for (const eventSource2 of Object.values(eventHub)) {
|
|
4040
|
+
eventSource2.clear();
|
|
4009
4041
|
}
|
|
4010
|
-
clearTimeout(context.timeoutHandles.reconnect);
|
|
4011
|
-
clearInterval(context.intervalHandles.heartbeat);
|
|
4012
|
-
connect();
|
|
4013
4042
|
}
|
|
4014
|
-
function
|
|
4015
|
-
if (
|
|
4016
|
-
|
|
4043
|
+
function reconnect() {
|
|
4044
|
+
if (context.socket) {
|
|
4045
|
+
context.socket.removeEventListener("open", onOpen);
|
|
4046
|
+
context.socket.removeEventListener("message", onMessage);
|
|
4047
|
+
context.socket.removeEventListener("close", onClose);
|
|
4048
|
+
context.socket.removeEventListener("error", onError);
|
|
4049
|
+
context.socket.close();
|
|
4050
|
+
context.socket = null;
|
|
4017
4051
|
}
|
|
4018
|
-
|
|
4019
|
-
|
|
4020
|
-
|
|
4021
|
-
|
|
4022
|
-
|
|
4023
|
-
|
|
4024
|
-
});
|
|
4025
|
-
notify(result.updates, batchedUpdatesWrapper);
|
|
4026
|
-
effects.send(messages);
|
|
4052
|
+
clearTimeout(context.timers.flush);
|
|
4053
|
+
clearTimeout(context.timers.reconnect);
|
|
4054
|
+
clearInterval(context.timers.heartbeat);
|
|
4055
|
+
clearTimeout(context.timers.pongTimeout);
|
|
4056
|
+
updateConnection({ status: "unavailable" }, batchUpdates);
|
|
4057
|
+
connect();
|
|
4027
4058
|
}
|
|
4028
4059
|
function tryFlushing() {
|
|
4029
4060
|
const storageOps = context.buffer.storageOperations;
|
|
4030
4061
|
if (storageOps.length > 0) {
|
|
4031
|
-
|
|
4062
|
+
for (const op of storageOps) {
|
|
4032
4063
|
context.unacknowledgedOps.set(nn(op.opId), op);
|
|
4033
|
-
}
|
|
4064
|
+
}
|
|
4034
4065
|
notifyStorageStatus();
|
|
4035
4066
|
}
|
|
4036
4067
|
if (context.socket === null || context.socket.readyState !== context.socket.OPEN) {
|
|
@@ -4038,78 +4069,54 @@ ${Array.from(traces).join("\n\n")}`
|
|
|
4038
4069
|
return;
|
|
4039
4070
|
}
|
|
4040
4071
|
const now = Date.now();
|
|
4041
|
-
const
|
|
4042
|
-
if (
|
|
4043
|
-
const
|
|
4044
|
-
if (
|
|
4072
|
+
const elapsedMillis = now - context.buffer.lastFlushedAt;
|
|
4073
|
+
if (elapsedMillis > config.throttleDelay) {
|
|
4074
|
+
const messagesToFlush = serializeBuffer();
|
|
4075
|
+
if (messagesToFlush.length === 0) {
|
|
4045
4076
|
return;
|
|
4046
4077
|
}
|
|
4047
|
-
effects.send(
|
|
4078
|
+
effects.send(messagesToFlush);
|
|
4048
4079
|
context.buffer = {
|
|
4080
|
+
lastFlushedAt: now,
|
|
4049
4081
|
messages: [],
|
|
4050
4082
|
storageOperations: [],
|
|
4051
4083
|
me: null
|
|
4052
4084
|
};
|
|
4053
|
-
context.lastFlushTime = now;
|
|
4054
4085
|
} else {
|
|
4055
|
-
|
|
4056
|
-
|
|
4057
|
-
|
|
4058
|
-
context.timeoutHandles.flush = effects.delayFlush(
|
|
4059
|
-
config.throttleDelay - (now - context.lastFlushTime)
|
|
4086
|
+
clearTimeout(context.timers.flush);
|
|
4087
|
+
context.timers.flush = effects.scheduleFlush(
|
|
4088
|
+
config.throttleDelay - elapsedMillis
|
|
4060
4089
|
);
|
|
4061
4090
|
}
|
|
4062
4091
|
}
|
|
4063
|
-
function
|
|
4092
|
+
function serializeBuffer() {
|
|
4064
4093
|
const messages = [];
|
|
4065
|
-
if (
|
|
4094
|
+
if (context.buffer.me) {
|
|
4066
4095
|
messages.push(
|
|
4067
|
-
|
|
4096
|
+
context.buffer.me.type === "full" ? {
|
|
4068
4097
|
type: 100 /* UPDATE_PRESENCE */,
|
|
4069
4098
|
// Populating the `targetActor` field turns this message into
|
|
4070
4099
|
// a Full Presence™ update message (not a patch), which will get
|
|
4071
4100
|
// interpreted by other clients as such.
|
|
4072
4101
|
targetActor: -1,
|
|
4073
|
-
data:
|
|
4102
|
+
data: context.buffer.me.data
|
|
4074
4103
|
} : {
|
|
4075
4104
|
type: 100 /* UPDATE_PRESENCE */,
|
|
4076
|
-
data:
|
|
4105
|
+
data: context.buffer.me.data
|
|
4077
4106
|
}
|
|
4078
4107
|
);
|
|
4079
4108
|
}
|
|
4080
|
-
for (const event of
|
|
4109
|
+
for (const event of context.buffer.messages) {
|
|
4081
4110
|
messages.push(event);
|
|
4082
4111
|
}
|
|
4083
|
-
if (
|
|
4112
|
+
if (context.buffer.storageOperations.length > 0) {
|
|
4084
4113
|
messages.push({
|
|
4085
4114
|
type: 201 /* UPDATE_STORAGE */,
|
|
4086
|
-
ops:
|
|
4115
|
+
ops: context.buffer.storageOperations
|
|
4087
4116
|
});
|
|
4088
4117
|
}
|
|
4089
4118
|
return messages;
|
|
4090
4119
|
}
|
|
4091
|
-
function disconnect() {
|
|
4092
|
-
if (context.socket) {
|
|
4093
|
-
context.socket.removeEventListener("open", onOpen);
|
|
4094
|
-
context.socket.removeEventListener("message", onMessage);
|
|
4095
|
-
context.socket.removeEventListener("close", onClose);
|
|
4096
|
-
context.socket.removeEventListener("error", onError);
|
|
4097
|
-
context.socket.close();
|
|
4098
|
-
context.socket = null;
|
|
4099
|
-
}
|
|
4100
|
-
batchUpdates(() => {
|
|
4101
|
-
updateConnection({ status: "closed" }, doNotBatchUpdates);
|
|
4102
|
-
if (context.timeoutHandles.flush) {
|
|
4103
|
-
clearTimeout(context.timeoutHandles.flush);
|
|
4104
|
-
}
|
|
4105
|
-
clearTimeout(context.timeoutHandles.reconnect);
|
|
4106
|
-
clearTimeout(context.timeoutHandles.pongTimeout);
|
|
4107
|
-
clearInterval(context.intervalHandles.heartbeat);
|
|
4108
|
-
context.others.clearOthers();
|
|
4109
|
-
notify({ others: [{ type: "reset" }] }, doNotBatchUpdates);
|
|
4110
|
-
Object.values(eventHub).forEach((eventSource2) => eventSource2.clear());
|
|
4111
|
-
});
|
|
4112
|
-
}
|
|
4113
4120
|
function broadcastEvent(event, options = {
|
|
4114
4121
|
shouldQueueEventIfNotReady: false
|
|
4115
4122
|
}) {
|
|
@@ -4183,9 +4190,6 @@ ${Array.from(traces).join("\n\n")}`
|
|
|
4183
4190
|
}
|
|
4184
4191
|
tryFlushing();
|
|
4185
4192
|
}
|
|
4186
|
-
function canUndo() {
|
|
4187
|
-
return context.undoStack.length > 0;
|
|
4188
|
-
}
|
|
4189
4193
|
function redo() {
|
|
4190
4194
|
if (context.activeBatch) {
|
|
4191
4195
|
throw new Error("redo is not allowed during a batch");
|
|
@@ -4208,9 +4212,6 @@ ${Array.from(traces).join("\n\n")}`
|
|
|
4208
4212
|
}
|
|
4209
4213
|
tryFlushing();
|
|
4210
4214
|
}
|
|
4211
|
-
function canRedo() {
|
|
4212
|
-
return context.redoStack.length > 0;
|
|
4213
|
-
}
|
|
4214
4215
|
function batch(callback) {
|
|
4215
4216
|
if (context.activeBatch) {
|
|
4216
4217
|
return callback();
|
|
@@ -4501,7 +4502,7 @@ function prepareCreateWebSocket(liveblocksServer, WebSocketPolyfill) {
|
|
|
4501
4502
|
// @ts-ignore (__PACKAGE_VERSION__ will be injected by the build script)
|
|
4502
4503
|
true ? (
|
|
4503
4504
|
/* istanbul ignore next */
|
|
4504
|
-
"1.0.
|
|
4505
|
+
"1.0.7-test1"
|
|
4505
4506
|
) : "dev"}`
|
|
4506
4507
|
);
|
|
4507
4508
|
};
|
|
@@ -5109,4 +5110,4 @@ function shallow(a, b) {
|
|
|
5109
5110
|
|
|
5110
5111
|
|
|
5111
5112
|
|
|
5112
|
-
exports.ClientMsgCode = ClientMsgCode; exports.CrdtType = CrdtType; exports.LiveList = LiveList; exports.LiveMap = LiveMap; exports.LiveObject = LiveObject; exports.OpCode = OpCode; exports.ServerMsgCode = ServerMsgCode; exports.WebsocketCloseCodes = WebsocketCloseCodes; exports.asArrayWithLegacyMethods = asArrayWithLegacyMethods; exports.
|
|
5113
|
+
exports.ClientMsgCode = ClientMsgCode; exports.CrdtType = CrdtType; exports.LiveList = LiveList; exports.LiveMap = LiveMap; exports.LiveObject = LiveObject; exports.OpCode = OpCode; exports.ServerMsgCode = ServerMsgCode; exports.WebsocketCloseCodes = WebsocketCloseCodes; exports.asArrayWithLegacyMethods = asArrayWithLegacyMethods; exports.asPos = asPos; exports.assert = assert; exports.assertNever = assertNever; exports.b64decode = b64decode; exports.createClient = createClient; exports.deprecate = deprecate; exports.deprecateIf = deprecateIf; exports.errorIf = errorIf; exports.freeze = freeze; exports.isAppOnlyAuthToken = isAppOnlyAuthToken; exports.isAuthToken = isAuthToken; exports.isChildCrdt = isChildCrdt; exports.isJsonArray = isJsonArray; exports.isJsonObject = isJsonObject; exports.isJsonScalar = isJsonScalar; exports.isPlainObject = isPlainObject; exports.isRoomAuthToken = isRoomAuthToken; exports.isRootCrdt = isRootCrdt; exports.legacy_patchImmutableObject = legacy_patchImmutableObject; exports.lsonToJson = lsonToJson; exports.makePosition = makePosition; exports.nn = nn; exports.patchLiveObjectKey = patchLiveObjectKey; exports.shallow = shallow; exports.throwUsageError = throwUsageError; exports.tryParseJson = tryParseJson;
|