@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.
Files changed (3) hide show
  1. package/dist/index.d.ts +81 -15
  2. package/dist/index.js +304 -303
  3. 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 function makePosition(before?: string, after?: string): string;
1240
- declare function comparePosition(posA: string, posB: string): number;
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, comparePosition, createClient, deprecate, deprecateIf, errorIf, freeze, isAppOnlyAuthToken, isAuthToken, isChildCrdt, isJsonArray, isJsonObject, isJsonScalar, isPlainObject, isRoomAuthToken, isRootCrdt, legacy_patchImmutableObject, lsonToJson, makePosition, nn, patchLiveObjectKey, shallow, throwUsageError, tryParseJson };
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.6-test3"
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 before = (_b = this._items[existingItemIndex]) == null ? void 0 : _b._getParentKeyOrThrow();
1112
- const after = (_c = this._items[existingItemIndex + 1]) == null ? void 0 : _c._getParentKeyOrThrow();
1113
- newKey = makePosition(before, after);
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 before = this._items[index - 1] ? this._items[index - 1]._getParentKeyOrThrow() : void 0;
1414
- const after = this._items[index] ? this._items[index]._getParentKeyOrThrow() : void 0;
1415
- const position = makePosition(before, after);
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]._getParentKeyOrThrow();
1457
- beforePosition = this._items[targetIndex]._getParentKeyOrThrow();
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]._getParentKeyOrThrow();
1460
- beforePosition = targetIndex === 0 ? void 0 : this._items[targetIndex - 1]._getParentKeyOrThrow();
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._getParentKeyOrThrow() : void 0
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
- numberOfRetry: 0,
3247
- lastFlushTime: 0,
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
- ops.forEach((op) => {
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
- storageUpdates.forEach((value, key) => {
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
- delayFlush(delay) {
3376
- return setTimeout(tryFlushing, delay);
3377
- },
3378
- startHeartbeatInterval() {
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 = load(message.items);
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.forEach((node, id) => {
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(op.parentKey, node, source);
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.numberOfRetry++;
3696
- context.timeoutHandles.reconnect = effects.scheduleReconnect(
3697
- getRetryDelay()
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.timeoutHandles.pongTimeout);
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.forEach((value, key) => {
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.timeoutHandles.pongTimeout);
3903
- clearInterval(context.intervalHandles.heartbeat);
3904
- if (context.timeoutHandles.flush) {
3905
- clearTimeout(context.timeoutHandles.flush);
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.numberOfRetry++;
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.timeoutHandles.reconnect = effects.scheduleReconnect(delay);
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.numberOfRetry++;
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.timeoutHandles.reconnect = effects.scheduleReconnect(delay);
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.numberOfRetry < BACKOFF_RETRY_DELAYS_SLOW.length ? context.numberOfRetry : BACKOFF_RETRY_DELAYS_SLOW.length - 1];
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.numberOfRetry < BACKOFF_RETRY_DELAYS.length ? context.numberOfRetry : BACKOFF_RETRY_DELAYS.length - 1];
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.intervalHandles.heartbeat);
3955
- context.intervalHandles.heartbeat = effects.startHeartbeatInterval();
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.numberOfRetry = 0;
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.timeoutHandles.pongTimeout);
3987
- context.timeoutHandles.pongTimeout = effects.schedulePongTimeout();
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 reconnect() {
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
- updateConnection({ status: "unavailable" }, batchUpdates);
4006
- clearTimeout(context.timeoutHandles.pongTimeout);
4007
- if (context.timeoutHandles.flush) {
4008
- clearTimeout(context.timeoutHandles.flush);
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 applyAndSendOps(offlineOps, batchedUpdatesWrapper) {
4015
- if (offlineOps.size === 0) {
4016
- return;
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
- const messages = [];
4019
- const ops = Array.from(offlineOps.values());
4020
- const result = applyOps(ops, true);
4021
- messages.push({
4022
- type: 201 /* UPDATE_STORAGE */,
4023
- ops: result.ops
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
- storageOps.forEach((op) => {
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 elapsedTime = now - context.lastFlushTime;
4042
- if (elapsedTime > config.throttleDelay) {
4043
- const messages = flushDataToMessages(context);
4044
- if (messages.length === 0) {
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(messages);
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
- if (context.timeoutHandles.flush !== null) {
4056
- clearTimeout(context.timeoutHandles.flush);
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 flushDataToMessages(state) {
4092
+ function serializeBuffer() {
4064
4093
  const messages = [];
4065
- if (state.buffer.me) {
4094
+ if (context.buffer.me) {
4066
4095
  messages.push(
4067
- state.buffer.me.type === "full" ? {
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: state.buffer.me.data
4102
+ data: context.buffer.me.data
4074
4103
  } : {
4075
4104
  type: 100 /* UPDATE_PRESENCE */,
4076
- data: state.buffer.me.data
4105
+ data: context.buffer.me.data
4077
4106
  }
4078
4107
  );
4079
4108
  }
4080
- for (const event of state.buffer.messages) {
4109
+ for (const event of context.buffer.messages) {
4081
4110
  messages.push(event);
4082
4111
  }
4083
- if (state.buffer.storageOperations.length > 0) {
4112
+ if (context.buffer.storageOperations.length > 0) {
4084
4113
  messages.push({
4085
4114
  type: 201 /* UPDATE_STORAGE */,
4086
- ops: state.buffer.storageOperations
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.6-test3"
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.assert = assert; exports.assertNever = assertNever; exports.b64decode = b64decode; exports.comparePosition = comparePosition; 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;
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;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@liveblocks/core",
3
- "version": "1.0.6-test3",
3
+ "version": "1.0.7-test1",
4
4
  "description": "Shared code and foundational internals for Liveblocks",
5
5
  "main": "./dist/index.js",
6
6
  "types": "./dist/index.d.ts",