@liveblocks/core 0.18.3 → 0.18.5

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.
@@ -997,9 +997,13 @@ var LiveList = class extends AbstractCrdt {
997
997
  return this._items.length;
998
998
  }
999
999
  push(element) {
1000
+ var _a;
1001
+ (_a = this._pool) == null ? void 0 : _a.assertStorageIsWritable();
1000
1002
  return this.insert(element, this.length);
1001
1003
  }
1002
1004
  insert(element, index) {
1005
+ var _a;
1006
+ (_a = this._pool) == null ? void 0 : _a.assertStorageIsWritable();
1003
1007
  if (index < 0 || index > this._items.length) {
1004
1008
  throw new Error(
1005
1009
  `Cannot insert list item at index "${index}". index should be between 0 and ${this._items.length}`
@@ -1024,6 +1028,8 @@ var LiveList = class extends AbstractCrdt {
1024
1028
  }
1025
1029
  }
1026
1030
  move(index, targetIndex) {
1031
+ var _a;
1032
+ (_a = this._pool) == null ? void 0 : _a.assertStorageIsWritable();
1027
1033
  if (targetIndex < 0) {
1028
1034
  throw new Error("targetIndex cannot be less than 0");
1029
1035
  }
@@ -1077,6 +1083,8 @@ var LiveList = class extends AbstractCrdt {
1077
1083
  }
1078
1084
  }
1079
1085
  delete(index) {
1086
+ var _a;
1087
+ (_a = this._pool) == null ? void 0 : _a.assertStorageIsWritable();
1080
1088
  if (index < 0 || index >= this._items.length) {
1081
1089
  throw new Error(
1082
1090
  `Cannot delete list item at index "${index}". index should be between 0 and ${this._items.length - 1}`
@@ -1109,6 +1117,8 @@ var LiveList = class extends AbstractCrdt {
1109
1117
  }
1110
1118
  }
1111
1119
  clear() {
1120
+ var _a;
1121
+ (_a = this._pool) == null ? void 0 : _a.assertStorageIsWritable();
1112
1122
  if (this._pool) {
1113
1123
  const ops = [];
1114
1124
  const reverseOps = [];
@@ -1142,6 +1152,8 @@ var LiveList = class extends AbstractCrdt {
1142
1152
  }
1143
1153
  }
1144
1154
  set(index, item) {
1155
+ var _a;
1156
+ (_a = this._pool) == null ? void 0 : _a.assertStorageIsWritable();
1145
1157
  if (index < 0 || index >= this._items.length) {
1146
1158
  throw new Error(
1147
1159
  `Cannot set list item at index "${index}". index should be between 0 and ${this._items.length - 1}`
@@ -1446,6 +1458,8 @@ var LiveMap = class extends AbstractCrdt {
1446
1458
  return liveNodeToLson(value);
1447
1459
  }
1448
1460
  set(key, value) {
1461
+ var _a;
1462
+ (_a = this._pool) == null ? void 0 : _a.assertStorageIsWritable();
1449
1463
  const oldValue = this._map.get(key);
1450
1464
  if (oldValue) {
1451
1465
  oldValue._detach();
@@ -1479,6 +1493,8 @@ var LiveMap = class extends AbstractCrdt {
1479
1493
  return this._map.has(key);
1480
1494
  }
1481
1495
  delete(key) {
1496
+ var _a;
1497
+ (_a = this._pool) == null ? void 0 : _a.assertStorageIsWritable();
1482
1498
  const item = this._map.get(key);
1483
1499
  if (item === void 0) {
1484
1500
  return false;
@@ -1849,12 +1865,16 @@ var LiveObject = class extends AbstractCrdt {
1849
1865
  return fromEntries(this._map);
1850
1866
  }
1851
1867
  set(key, value) {
1868
+ var _a;
1869
+ (_a = this._pool) == null ? void 0 : _a.assertStorageIsWritable();
1852
1870
  this.update({ [key]: value });
1853
1871
  }
1854
1872
  get(key) {
1855
1873
  return this._map.get(key);
1856
1874
  }
1857
1875
  delete(key) {
1876
+ var _a;
1877
+ (_a = this._pool) == null ? void 0 : _a.assertStorageIsWritable();
1858
1878
  const keyAsString = key;
1859
1879
  const oldValue = this._map.get(keyAsString);
1860
1880
  if (oldValue === void 0) {
@@ -1903,6 +1923,8 @@ var LiveObject = class extends AbstractCrdt {
1903
1923
  );
1904
1924
  }
1905
1925
  update(patch) {
1926
+ var _a;
1927
+ (_a = this._pool) == null ? void 0 : _a.assertStorageIsWritable();
1906
1928
  if (this._pool === void 0 || this._id === void 0) {
1907
1929
  for (const key in patch) {
1908
1930
  const newValue = patch[key];
@@ -2392,418 +2414,107 @@ function errorIf(condition, message) {
2392
2414
  }
2393
2415
  }
2394
2416
 
2395
- // src/immutable.ts
2396
- function lsonObjectToJson(obj) {
2397
- const result = {};
2398
- for (const key in obj) {
2399
- const val = obj[key];
2400
- if (val !== void 0) {
2401
- result[key] = lsonToJson(val);
2402
- }
2417
+ // src/EventSource.ts
2418
+ function makeEventSource() {
2419
+ const _onetimeObservers = /* @__PURE__ */ new Set();
2420
+ const _observers = /* @__PURE__ */ new Set();
2421
+ function subscribe(callback) {
2422
+ _observers.add(callback);
2423
+ return () => _observers.delete(callback);
2403
2424
  }
2404
- return result;
2405
- }
2406
- function liveObjectToJson(liveObject) {
2407
- return lsonObjectToJson(liveObject.toObject());
2408
- }
2409
- function liveMapToJson(map) {
2410
- const result = {};
2411
- for (const [key, value] of map.entries()) {
2412
- result[key] = lsonToJson(value);
2425
+ function subscribeOnce(callback) {
2426
+ _onetimeObservers.add(callback);
2427
+ return () => _onetimeObservers.delete(callback);
2413
2428
  }
2414
- return result;
2415
- }
2416
- function lsonListToJson(value) {
2417
- return value.map(lsonToJson);
2418
- }
2419
- function liveListToJson(value) {
2420
- return lsonListToJson(value.toArray());
2421
- }
2422
- function lsonToJson(value) {
2423
- if (value instanceof LiveObject) {
2424
- return liveObjectToJson(value);
2425
- } else if (value instanceof LiveList) {
2426
- return liveListToJson(value);
2427
- } else if (value instanceof LiveMap) {
2428
- return liveMapToJson(value);
2429
- } else if (value instanceof LiveRegister) {
2430
- return value.data;
2429
+ function notify(event) {
2430
+ _onetimeObservers.forEach((callback) => callback(event));
2431
+ _onetimeObservers.clear();
2432
+ _observers.forEach((callback) => callback(event));
2431
2433
  }
2432
- if (Array.isArray(value)) {
2433
- return lsonListToJson(value);
2434
- } else if (isPlainObject(value)) {
2435
- return lsonObjectToJson(value);
2434
+ function clear() {
2435
+ _onetimeObservers.clear();
2436
+ _observers.clear();
2436
2437
  }
2437
- return value;
2438
+ return {
2439
+ notify,
2440
+ subscribe,
2441
+ subscribeOnce,
2442
+ clear,
2443
+ observable: {
2444
+ subscribe,
2445
+ subscribeOnce
2446
+ }
2447
+ };
2438
2448
  }
2439
- function deepLiveify(value) {
2440
- if (Array.isArray(value)) {
2441
- return new LiveList(value.map(deepLiveify));
2442
- } else if (isPlainObject(value)) {
2443
- const init = {};
2444
- for (const key in value) {
2445
- const val = value[key];
2449
+
2450
+ // src/ImmutableRef.ts
2451
+ function merge(target, patch) {
2452
+ let updated = false;
2453
+ const newValue = __spreadValues({}, target);
2454
+ Object.keys(patch).forEach((k) => {
2455
+ const key = k;
2456
+ const val = patch[key];
2457
+ if (newValue[key] !== val) {
2446
2458
  if (val === void 0) {
2447
- continue;
2459
+ delete newValue[key];
2460
+ } else {
2461
+ newValue[key] = val;
2448
2462
  }
2449
- init[key] = deepLiveify(val);
2463
+ updated = true;
2450
2464
  }
2451
- return new LiveObject(init);
2452
- } else {
2453
- return value;
2454
- }
2465
+ });
2466
+ return updated ? newValue : target;
2455
2467
  }
2456
- function patchLiveList(liveList, prev, next) {
2457
- let i = 0;
2458
- let prevEnd = prev.length - 1;
2459
- let nextEnd = next.length - 1;
2460
- let prevNode = prev[0];
2461
- let nextNode = next[0];
2462
- outer: {
2463
- while (prevNode === nextNode) {
2464
- ++i;
2465
- if (i > prevEnd || i > nextEnd) {
2466
- break outer;
2467
- }
2468
- prevNode = prev[i];
2469
- nextNode = next[i];
2470
- }
2471
- prevNode = prev[prevEnd];
2472
- nextNode = next[nextEnd];
2473
- while (prevNode === nextNode) {
2474
- prevEnd--;
2475
- nextEnd--;
2476
- if (i > prevEnd || i > nextEnd) {
2477
- break outer;
2478
- }
2479
- prevNode = prev[prevEnd];
2480
- nextNode = next[nextEnd];
2481
- }
2468
+ var ImmutableRef = class {
2469
+ constructor() {
2470
+ this._ev = makeEventSource();
2482
2471
  }
2483
- if (i > prevEnd) {
2484
- if (i <= nextEnd) {
2485
- while (i <= nextEnd) {
2486
- liveList.insert(deepLiveify(next[i]), i);
2487
- i++;
2488
- }
2489
- }
2490
- } else if (i > nextEnd) {
2491
- let localI = i;
2492
- while (localI <= prevEnd) {
2493
- liveList.delete(i);
2494
- localI++;
2495
- }
2496
- } else {
2497
- while (i <= prevEnd && i <= nextEnd) {
2498
- prevNode = prev[i];
2499
- nextNode = next[i];
2500
- const liveListNode = liveList.get(i);
2501
- if (isLiveObject(liveListNode) && isPlainObject(prevNode) && isPlainObject(nextNode)) {
2502
- patchLiveObject(liveListNode, prevNode, nextNode);
2503
- } else {
2504
- liveList.set(i, deepLiveify(nextNode));
2505
- }
2506
- i++;
2507
- }
2508
- while (i <= nextEnd) {
2509
- liveList.insert(deepLiveify(next[i]), i);
2510
- i++;
2511
- }
2512
- let localI = i;
2513
- while (localI <= prevEnd) {
2514
- liveList.delete(i);
2515
- localI++;
2516
- }
2472
+ get didInvalidate() {
2473
+ return this._ev.observable;
2517
2474
  }
2518
- }
2519
- function patchLiveObjectKey(liveObject, key, prev, next) {
2520
- if (process.env.NODE_ENV !== "production") {
2521
- const nonSerializableValue = findNonSerializableValue(next);
2522
- if (nonSerializableValue) {
2523
- error(
2524
- `New state path: '${nonSerializableValue.path}' value: '${nonSerializableValue.value}' is not serializable.
2525
- Only serializable value can be synced with Liveblocks.`
2526
- );
2527
- return;
2475
+ invalidate() {
2476
+ if (this._cache !== void 0) {
2477
+ this._cache = void 0;
2478
+ this._ev.notify();
2528
2479
  }
2529
2480
  }
2530
- const value = liveObject.get(key);
2531
- if (next === void 0) {
2532
- liveObject.delete(key);
2533
- } else if (value === void 0) {
2534
- liveObject.set(key, deepLiveify(next));
2535
- } else if (prev === next) {
2536
- return;
2537
- } else if (isLiveList(value) && Array.isArray(prev) && Array.isArray(next)) {
2538
- patchLiveList(value, prev, next);
2539
- } else if (isLiveObject(value) && isPlainObject(prev) && isPlainObject(next)) {
2540
- patchLiveObject(value, prev, next);
2541
- } else {
2542
- liveObject.set(key, deepLiveify(next));
2543
- }
2544
- }
2545
- function patchLiveObject(root, prev, next) {
2546
- const updates = {};
2547
- for (const key in next) {
2548
- patchLiveObjectKey(root, key, prev[key], next[key]);
2481
+ get current() {
2482
+ var _a;
2483
+ return (_a = this._cache) != null ? _a : this._cache = this._toImmutable();
2549
2484
  }
2550
- for (const key in prev) {
2551
- if (next[key] === void 0) {
2552
- root.delete(key);
2553
- }
2485
+ };
2486
+
2487
+ // src/MeRef.ts
2488
+ var MeRef = class extends ImmutableRef {
2489
+ constructor(initialPresence) {
2490
+ super();
2491
+ this._me = freeze(compactObject(initialPresence));
2554
2492
  }
2555
- if (Object.keys(updates).length > 0) {
2556
- root.update(updates);
2493
+ _toImmutable() {
2494
+ return this._me;
2557
2495
  }
2558
- }
2559
- function getParentsPath(node) {
2560
- const path = [];
2561
- while (node.parent.type === "HasParent") {
2562
- if (isLiveList(node.parent.node)) {
2563
- path.push(node.parent.node._indexOfPosition(node.parent.key));
2564
- } else {
2565
- path.push(node.parent.key);
2496
+ patch(patch) {
2497
+ const oldMe = this._me;
2498
+ const newMe = merge(oldMe, patch);
2499
+ if (oldMe !== newMe) {
2500
+ this._me = freeze(newMe);
2501
+ this.invalidate();
2566
2502
  }
2567
- node = node.parent.node;
2568
2503
  }
2569
- return path;
2570
- }
2571
- function legacy_patchImmutableObject(state, updates) {
2572
- return updates.reduce(
2573
- (state2, update) => legacy_patchImmutableObjectWithUpdate(state2, update),
2574
- state
2575
- );
2504
+ };
2505
+
2506
+ // src/LegacyArray.ts
2507
+ function asArrayWithLegacyMethods(arr) {
2508
+ Object.defineProperty(arr, "count", {
2509
+ value: arr.length,
2510
+ enumerable: false
2511
+ });
2512
+ Object.defineProperty(arr, "toArray", {
2513
+ value: () => arr,
2514
+ enumerable: false
2515
+ });
2516
+ return freeze(arr);
2576
2517
  }
2577
- function legacy_patchImmutableObjectWithUpdate(state, update) {
2578
- const path = getParentsPath(update.node);
2579
- return legacy_patchImmutableNode(state, path, update);
2580
- }
2581
- function legacy_patchImmutableNode(state, path, update) {
2582
- var _a, _b, _c, _d;
2583
- const pathItem = path.pop();
2584
- if (pathItem === void 0) {
2585
- switch (update.type) {
2586
- case "LiveObject": {
2587
- if (state === null || typeof state !== "object" || Array.isArray(state)) {
2588
- throw new Error(
2589
- "Internal: received update on LiveObject but state was not an object"
2590
- );
2591
- }
2592
- const newState = Object.assign({}, state);
2593
- for (const key in update.updates) {
2594
- if (((_a = update.updates[key]) == null ? void 0 : _a.type) === "update") {
2595
- const val = update.node.get(key);
2596
- if (val !== void 0) {
2597
- newState[key] = lsonToJson(val);
2598
- }
2599
- } else if (((_b = update.updates[key]) == null ? void 0 : _b.type) === "delete") {
2600
- delete newState[key];
2601
- }
2602
- }
2603
- return newState;
2604
- }
2605
- case "LiveList": {
2606
- if (!Array.isArray(state)) {
2607
- throw new Error(
2608
- "Internal: received update on LiveList but state was not an array"
2609
- );
2610
- }
2611
- let newState = state.map((x) => x);
2612
- for (const listUpdate of update.updates) {
2613
- if (listUpdate.type === "set") {
2614
- newState = newState.map(
2615
- (item, index) => index === listUpdate.index ? lsonToJson(listUpdate.item) : item
2616
- );
2617
- } else if (listUpdate.type === "insert") {
2618
- if (listUpdate.index === newState.length) {
2619
- newState.push(lsonToJson(listUpdate.item));
2620
- } else {
2621
- newState = [
2622
- ...newState.slice(0, listUpdate.index),
2623
- lsonToJson(listUpdate.item),
2624
- ...newState.slice(listUpdate.index)
2625
- ];
2626
- }
2627
- } else if (listUpdate.type === "delete") {
2628
- newState.splice(listUpdate.index, 1);
2629
- } else if (listUpdate.type === "move") {
2630
- if (listUpdate.previousIndex > listUpdate.index) {
2631
- newState = [
2632
- ...newState.slice(0, listUpdate.index),
2633
- lsonToJson(listUpdate.item),
2634
- ...newState.slice(listUpdate.index, listUpdate.previousIndex),
2635
- ...newState.slice(listUpdate.previousIndex + 1)
2636
- ];
2637
- } else {
2638
- newState = [
2639
- ...newState.slice(0, listUpdate.previousIndex),
2640
- ...newState.slice(
2641
- listUpdate.previousIndex + 1,
2642
- listUpdate.index + 1
2643
- ),
2644
- lsonToJson(listUpdate.item),
2645
- ...newState.slice(listUpdate.index + 1)
2646
- ];
2647
- }
2648
- }
2649
- }
2650
- return newState;
2651
- }
2652
- case "LiveMap": {
2653
- if (state === null || typeof state !== "object" || Array.isArray(state)) {
2654
- throw new Error(
2655
- "Internal: received update on LiveMap but state was not an object"
2656
- );
2657
- }
2658
- const newState = Object.assign({}, state);
2659
- for (const key in update.updates) {
2660
- if (((_c = update.updates[key]) == null ? void 0 : _c.type) === "update") {
2661
- const value = update.node.get(key);
2662
- if (value !== void 0) {
2663
- newState[key] = lsonToJson(value);
2664
- }
2665
- } else if (((_d = update.updates[key]) == null ? void 0 : _d.type) === "delete") {
2666
- delete newState[key];
2667
- }
2668
- }
2669
- return newState;
2670
- }
2671
- }
2672
- }
2673
- if (Array.isArray(state)) {
2674
- const newArray = [...state];
2675
- newArray[pathItem] = legacy_patchImmutableNode(
2676
- state[pathItem],
2677
- path,
2678
- update
2679
- );
2680
- return newArray;
2681
- } else if (state !== null && typeof state === "object") {
2682
- const node = state[pathItem];
2683
- if (node === void 0) {
2684
- return state;
2685
- } else {
2686
- return __spreadProps(__spreadValues({}, state), {
2687
- [pathItem]: legacy_patchImmutableNode(node, path, update)
2688
- });
2689
- }
2690
- } else {
2691
- return state;
2692
- }
2693
- }
2694
-
2695
- // src/LegacyArray.ts
2696
- function asArrayWithLegacyMethods(arr) {
2697
- Object.defineProperty(arr, "count", {
2698
- value: arr.length,
2699
- enumerable: false
2700
- });
2701
- Object.defineProperty(arr, "toArray", {
2702
- value: () => arr,
2703
- enumerable: false
2704
- });
2705
- return freeze(arr);
2706
- }
2707
-
2708
- // src/types/Json.ts
2709
- function isJsonScalar(data) {
2710
- return data === null || typeof data === "string" || typeof data === "number" || typeof data === "boolean";
2711
- }
2712
- function isJsonArray(data) {
2713
- return Array.isArray(data);
2714
- }
2715
- function isJsonObject(data) {
2716
- return !isJsonScalar(data) && !isJsonArray(data);
2717
- }
2718
-
2719
- // src/EventSource.ts
2720
- function makeEventSource() {
2721
- const _onetimeObservers = /* @__PURE__ */ new Set();
2722
- const _observers = /* @__PURE__ */ new Set();
2723
- function subscribe(callback) {
2724
- _observers.add(callback);
2725
- return () => _observers.delete(callback);
2726
- }
2727
- function subscribeOnce(callback) {
2728
- _onetimeObservers.add(callback);
2729
- return () => _onetimeObservers.delete(callback);
2730
- }
2731
- function notify(event) {
2732
- _onetimeObservers.forEach((callback) => callback(event));
2733
- _onetimeObservers.clear();
2734
- _observers.forEach((callback) => callback(event));
2735
- }
2736
- function clear() {
2737
- _onetimeObservers.clear();
2738
- _observers.clear();
2739
- }
2740
- return {
2741
- notify,
2742
- subscribe,
2743
- subscribeOnce,
2744
- clear,
2745
- observable: {
2746
- subscribe,
2747
- subscribeOnce
2748
- }
2749
- };
2750
- }
2751
-
2752
- // src/ImmutableRef.ts
2753
- function merge(target, patch) {
2754
- let updated = false;
2755
- const newValue = __spreadValues({}, target);
2756
- Object.keys(patch).forEach((k) => {
2757
- const key = k;
2758
- const val = patch[key];
2759
- if (newValue[key] !== val) {
2760
- if (val === void 0) {
2761
- delete newValue[key];
2762
- } else {
2763
- newValue[key] = val;
2764
- }
2765
- updated = true;
2766
- }
2767
- });
2768
- return updated ? newValue : target;
2769
- }
2770
- var ImmutableRef = class {
2771
- constructor() {
2772
- this._ev = makeEventSource();
2773
- }
2774
- get didInvalidate() {
2775
- return this._ev.observable;
2776
- }
2777
- invalidate() {
2778
- if (this._cache !== void 0) {
2779
- this._cache = void 0;
2780
- this._ev.notify();
2781
- }
2782
- }
2783
- get current() {
2784
- var _a;
2785
- return (_a = this._cache) != null ? _a : this._cache = this._toImmutable();
2786
- }
2787
- };
2788
-
2789
- // src/MeRef.ts
2790
- var MeRef = class extends ImmutableRef {
2791
- constructor(initialPresence) {
2792
- super();
2793
- this._me = freeze(compactObject(initialPresence));
2794
- }
2795
- _toImmutable() {
2796
- return this._me;
2797
- }
2798
- patch(patch) {
2799
- const oldMe = this._me;
2800
- const newMe = merge(oldMe, patch);
2801
- if (oldMe !== newMe) {
2802
- this._me = freeze(newMe);
2803
- this.invalidate();
2804
- }
2805
- }
2806
- };
2807
2518
 
2808
2519
  // src/OthersRef.ts
2809
2520
  function makeUser(conn, presence) {
@@ -2856,11 +2567,12 @@ var OthersRef = class extends ImmutableRef {
2856
2567
  }
2857
2568
  this.invalidate();
2858
2569
  }
2859
- setConnection(connectionId, metaUserId, metaUserInfo) {
2570
+ setConnection(connectionId, metaUserId, metaUserInfo, metaIsReadonly) {
2860
2571
  this._connections[connectionId] = freeze({
2861
2572
  connectionId,
2862
2573
  id: metaUserId,
2863
- info: metaUserInfo
2574
+ info: metaUserInfo,
2575
+ isReadOnly: metaIsReadonly
2864
2576
  });
2865
2577
  if (this._presences[connectionId] !== void 0) {
2866
2578
  this._invalidateUser(connectionId);
@@ -2890,6 +2602,17 @@ var OthersRef = class extends ImmutableRef {
2890
2602
  }
2891
2603
  };
2892
2604
 
2605
+ // src/types/Json.ts
2606
+ function isJsonScalar(data) {
2607
+ return data === null || typeof data === "string" || typeof data === "number" || typeof data === "boolean";
2608
+ }
2609
+ function isJsonArray(data) {
2610
+ return Array.isArray(data);
2611
+ }
2612
+ function isJsonObject(data) {
2613
+ return !isJsonScalar(data) && !isJsonArray(data);
2614
+ }
2615
+
2893
2616
  // src/ValueRef.ts
2894
2617
  var ValueRef = class extends ImmutableRef {
2895
2618
  constructor(initialValue) {
@@ -2966,6 +2689,13 @@ function makeStateMachine(state, config, mockedEffects) {
2966
2689
  notify({ storageUpdates }, doNotBatchUpdates);
2967
2690
  });
2968
2691
  }
2692
+ },
2693
+ assertStorageIsWritable: () => {
2694
+ if (isConnectionSelfAware(state.connection.current) && state.connection.current.isReadOnly) {
2695
+ throw new Error(
2696
+ "Cannot write to storage with a read only user, please ensure the user has write permissions"
2697
+ );
2698
+ }
2969
2699
  }
2970
2700
  };
2971
2701
  const eventHub = {
@@ -3027,7 +2757,8 @@ function makeStateMachine(state, config, mockedEffects) {
3027
2757
  connectionId: conn.id,
3028
2758
  id: conn.userId,
3029
2759
  info: conn.userInfo,
3030
- presence: me
2760
+ presence: me,
2761
+ isReadOnly: conn.isReadOnly
3031
2762
  } : null
3032
2763
  );
3033
2764
  function createOrUpdateRootFromMessage(message, batchedUpdatesWrapper) {
@@ -3360,6 +3091,9 @@ function makeStateMachine(state, config, mockedEffects) {
3360
3091
  });
3361
3092
  }
3362
3093
  }
3094
+ function isStorageReadOnly(scopes) {
3095
+ return scopes.includes("room:read" /* Read */) && scopes.includes("room:presence:write" /* PresenceWrite */) && !scopes.includes("room:write" /* Write */);
3096
+ }
3363
3097
  function authenticationSuccess(token, socket) {
3364
3098
  socket.addEventListener("message", onMessage);
3365
3099
  socket.addEventListener("open", onOpen);
@@ -3370,7 +3104,8 @@ function makeStateMachine(state, config, mockedEffects) {
3370
3104
  state: "connecting",
3371
3105
  id: token.actor,
3372
3106
  userInfo: token.info,
3373
- userId: token.id
3107
+ userId: token.id,
3108
+ isReadOnly: isStorageReadOnly(token.scopes)
3374
3109
  },
3375
3110
  batchUpdates
3376
3111
  );
@@ -3426,7 +3161,12 @@ function makeStateMachine(state, config, mockedEffects) {
3426
3161
  for (const key in message.users) {
3427
3162
  const user = message.users[key];
3428
3163
  const connectionId = Number(key);
3429
- state.others.setConnection(connectionId, user.id, user.info);
3164
+ state.others.setConnection(
3165
+ connectionId,
3166
+ user.id,
3167
+ user.info,
3168
+ isStorageReadOnly(user.scopes)
3169
+ );
3430
3170
  }
3431
3171
  return { type: "reset" };
3432
3172
  }
@@ -3442,7 +3182,12 @@ function makeStateMachine(state, config, mockedEffects) {
3442
3182
  });
3443
3183
  }
3444
3184
  function onUserJoinedMessage(message) {
3445
- state.others.setConnection(message.actor, message.id, message.info);
3185
+ state.others.setConnection(
3186
+ message.actor,
3187
+ message.id,
3188
+ message.info,
3189
+ isStorageReadOnly(message.scopes)
3190
+ );
3446
3191
  state.buffer.messages.push({
3447
3192
  type: 100 /* UPDATE_PRESENCE */,
3448
3193
  data: state.me.current,
@@ -3856,7 +3601,7 @@ function makeStateMachine(state, config, mockedEffects) {
3856
3601
  if (state.activeBatch) {
3857
3602
  return callback();
3858
3603
  }
3859
- let rv = void 0;
3604
+ let returnValue = void 0;
3860
3605
  batchUpdates(() => {
3861
3606
  state.activeBatch = {
3862
3607
  ops: [],
@@ -3868,7 +3613,7 @@ function makeStateMachine(state, config, mockedEffects) {
3868
3613
  reverseOps: []
3869
3614
  };
3870
3615
  try {
3871
- rv = callback();
3616
+ returnValue = callback();
3872
3617
  } finally {
3873
3618
  const currentBatch = state.activeBatch;
3874
3619
  state.activeBatch = null;
@@ -3885,7 +3630,7 @@ function makeStateMachine(state, config, mockedEffects) {
3885
3630
  tryFlushing();
3886
3631
  }
3887
3632
  });
3888
- return rv;
3633
+ return returnValue;
3889
3634
  }
3890
3635
  function pauseHistory() {
3891
3636
  state.pausedHistory = [];
@@ -4048,7 +3793,7 @@ function prepareCreateWebSocket(liveblocksServer, WebSocketPolyfill) {
4048
3793
  const ws = WebSocketPolyfill || WebSocket;
4049
3794
  return (token) => {
4050
3795
  return new ws(
4051
- `${liveblocksServer}/?token=${token}&version=${true ? "0.18.3" : "dev"}`
3796
+ `${liveblocksServer}/?token=${token}&version=${true ? "0.18.5" : "dev"}`
4052
3797
  );
4053
3798
  };
4054
3799
  }
@@ -4266,6 +4011,306 @@ function buildLiveblocksPublicAuthorizeEndpoint(options, roomId) {
4266
4011
  )}/public/authorize`;
4267
4012
  }
4268
4013
 
4014
+ // src/immutable.ts
4015
+ function lsonObjectToJson(obj) {
4016
+ const result = {};
4017
+ for (const key in obj) {
4018
+ const val = obj[key];
4019
+ if (val !== void 0) {
4020
+ result[key] = lsonToJson(val);
4021
+ }
4022
+ }
4023
+ return result;
4024
+ }
4025
+ function liveObjectToJson(liveObject) {
4026
+ return lsonObjectToJson(liveObject.toObject());
4027
+ }
4028
+ function liveMapToJson(map) {
4029
+ const result = {};
4030
+ for (const [key, value] of map.entries()) {
4031
+ result[key] = lsonToJson(value);
4032
+ }
4033
+ return result;
4034
+ }
4035
+ function lsonListToJson(value) {
4036
+ return value.map(lsonToJson);
4037
+ }
4038
+ function liveListToJson(value) {
4039
+ return lsonListToJson(value.toArray());
4040
+ }
4041
+ function lsonToJson(value) {
4042
+ if (value instanceof LiveObject) {
4043
+ return liveObjectToJson(value);
4044
+ } else if (value instanceof LiveList) {
4045
+ return liveListToJson(value);
4046
+ } else if (value instanceof LiveMap) {
4047
+ return liveMapToJson(value);
4048
+ } else if (value instanceof LiveRegister) {
4049
+ return value.data;
4050
+ }
4051
+ if (Array.isArray(value)) {
4052
+ return lsonListToJson(value);
4053
+ } else if (isPlainObject(value)) {
4054
+ return lsonObjectToJson(value);
4055
+ }
4056
+ return value;
4057
+ }
4058
+ function deepLiveify(value) {
4059
+ if (Array.isArray(value)) {
4060
+ return new LiveList(value.map(deepLiveify));
4061
+ } else if (isPlainObject(value)) {
4062
+ const init = {};
4063
+ for (const key in value) {
4064
+ const val = value[key];
4065
+ if (val === void 0) {
4066
+ continue;
4067
+ }
4068
+ init[key] = deepLiveify(val);
4069
+ }
4070
+ return new LiveObject(init);
4071
+ } else {
4072
+ return value;
4073
+ }
4074
+ }
4075
+ function patchLiveList(liveList, prev, next) {
4076
+ let i = 0;
4077
+ let prevEnd = prev.length - 1;
4078
+ let nextEnd = next.length - 1;
4079
+ let prevNode = prev[0];
4080
+ let nextNode = next[0];
4081
+ outer: {
4082
+ while (prevNode === nextNode) {
4083
+ ++i;
4084
+ if (i > prevEnd || i > nextEnd) {
4085
+ break outer;
4086
+ }
4087
+ prevNode = prev[i];
4088
+ nextNode = next[i];
4089
+ }
4090
+ prevNode = prev[prevEnd];
4091
+ nextNode = next[nextEnd];
4092
+ while (prevNode === nextNode) {
4093
+ prevEnd--;
4094
+ nextEnd--;
4095
+ if (i > prevEnd || i > nextEnd) {
4096
+ break outer;
4097
+ }
4098
+ prevNode = prev[prevEnd];
4099
+ nextNode = next[nextEnd];
4100
+ }
4101
+ }
4102
+ if (i > prevEnd) {
4103
+ if (i <= nextEnd) {
4104
+ while (i <= nextEnd) {
4105
+ liveList.insert(deepLiveify(next[i]), i);
4106
+ i++;
4107
+ }
4108
+ }
4109
+ } else if (i > nextEnd) {
4110
+ let localI = i;
4111
+ while (localI <= prevEnd) {
4112
+ liveList.delete(i);
4113
+ localI++;
4114
+ }
4115
+ } else {
4116
+ while (i <= prevEnd && i <= nextEnd) {
4117
+ prevNode = prev[i];
4118
+ nextNode = next[i];
4119
+ const liveListNode = liveList.get(i);
4120
+ if (isLiveObject(liveListNode) && isPlainObject(prevNode) && isPlainObject(nextNode)) {
4121
+ patchLiveObject(liveListNode, prevNode, nextNode);
4122
+ } else {
4123
+ liveList.set(i, deepLiveify(nextNode));
4124
+ }
4125
+ i++;
4126
+ }
4127
+ while (i <= nextEnd) {
4128
+ liveList.insert(deepLiveify(next[i]), i);
4129
+ i++;
4130
+ }
4131
+ let localI = i;
4132
+ while (localI <= prevEnd) {
4133
+ liveList.delete(i);
4134
+ localI++;
4135
+ }
4136
+ }
4137
+ }
4138
+ function patchLiveObjectKey(liveObject, key, prev, next) {
4139
+ if (process.env.NODE_ENV !== "production") {
4140
+ const nonSerializableValue = findNonSerializableValue(next);
4141
+ if (nonSerializableValue) {
4142
+ error(
4143
+ `New state path: '${nonSerializableValue.path}' value: '${nonSerializableValue.value}' is not serializable.
4144
+ Only serializable value can be synced with Liveblocks.`
4145
+ );
4146
+ return;
4147
+ }
4148
+ }
4149
+ const value = liveObject.get(key);
4150
+ if (next === void 0) {
4151
+ liveObject.delete(key);
4152
+ } else if (value === void 0) {
4153
+ liveObject.set(key, deepLiveify(next));
4154
+ } else if (prev === next) {
4155
+ return;
4156
+ } else if (isLiveList(value) && Array.isArray(prev) && Array.isArray(next)) {
4157
+ patchLiveList(value, prev, next);
4158
+ } else if (isLiveObject(value) && isPlainObject(prev) && isPlainObject(next)) {
4159
+ patchLiveObject(value, prev, next);
4160
+ } else {
4161
+ liveObject.set(key, deepLiveify(next));
4162
+ }
4163
+ }
4164
+ function patchLiveObject(root, prev, next) {
4165
+ const updates = {};
4166
+ for (const key in next) {
4167
+ patchLiveObjectKey(root, key, prev[key], next[key]);
4168
+ }
4169
+ for (const key in prev) {
4170
+ if (next[key] === void 0) {
4171
+ root.delete(key);
4172
+ }
4173
+ }
4174
+ if (Object.keys(updates).length > 0) {
4175
+ root.update(updates);
4176
+ }
4177
+ }
4178
+ function getParentsPath(node) {
4179
+ const path = [];
4180
+ while (node.parent.type === "HasParent") {
4181
+ if (isLiveList(node.parent.node)) {
4182
+ path.push(node.parent.node._indexOfPosition(node.parent.key));
4183
+ } else {
4184
+ path.push(node.parent.key);
4185
+ }
4186
+ node = node.parent.node;
4187
+ }
4188
+ return path;
4189
+ }
4190
+ function legacy_patchImmutableObject(state, updates) {
4191
+ return updates.reduce(
4192
+ (state2, update) => legacy_patchImmutableObjectWithUpdate(state2, update),
4193
+ state
4194
+ );
4195
+ }
4196
+ function legacy_patchImmutableObjectWithUpdate(state, update) {
4197
+ const path = getParentsPath(update.node);
4198
+ return legacy_patchImmutableNode(state, path, update);
4199
+ }
4200
+ function legacy_patchImmutableNode(state, path, update) {
4201
+ var _a, _b, _c, _d;
4202
+ const pathItem = path.pop();
4203
+ if (pathItem === void 0) {
4204
+ switch (update.type) {
4205
+ case "LiveObject": {
4206
+ if (state === null || typeof state !== "object" || Array.isArray(state)) {
4207
+ throw new Error(
4208
+ "Internal: received update on LiveObject but state was not an object"
4209
+ );
4210
+ }
4211
+ const newState = Object.assign({}, state);
4212
+ for (const key in update.updates) {
4213
+ if (((_a = update.updates[key]) == null ? void 0 : _a.type) === "update") {
4214
+ const val = update.node.get(key);
4215
+ if (val !== void 0) {
4216
+ newState[key] = lsonToJson(val);
4217
+ }
4218
+ } else if (((_b = update.updates[key]) == null ? void 0 : _b.type) === "delete") {
4219
+ delete newState[key];
4220
+ }
4221
+ }
4222
+ return newState;
4223
+ }
4224
+ case "LiveList": {
4225
+ if (!Array.isArray(state)) {
4226
+ throw new Error(
4227
+ "Internal: received update on LiveList but state was not an array"
4228
+ );
4229
+ }
4230
+ let newState = state.map((x) => x);
4231
+ for (const listUpdate of update.updates) {
4232
+ if (listUpdate.type === "set") {
4233
+ newState = newState.map(
4234
+ (item, index) => index === listUpdate.index ? lsonToJson(listUpdate.item) : item
4235
+ );
4236
+ } else if (listUpdate.type === "insert") {
4237
+ if (listUpdate.index === newState.length) {
4238
+ newState.push(lsonToJson(listUpdate.item));
4239
+ } else {
4240
+ newState = [
4241
+ ...newState.slice(0, listUpdate.index),
4242
+ lsonToJson(listUpdate.item),
4243
+ ...newState.slice(listUpdate.index)
4244
+ ];
4245
+ }
4246
+ } else if (listUpdate.type === "delete") {
4247
+ newState.splice(listUpdate.index, 1);
4248
+ } else if (listUpdate.type === "move") {
4249
+ if (listUpdate.previousIndex > listUpdate.index) {
4250
+ newState = [
4251
+ ...newState.slice(0, listUpdate.index),
4252
+ lsonToJson(listUpdate.item),
4253
+ ...newState.slice(listUpdate.index, listUpdate.previousIndex),
4254
+ ...newState.slice(listUpdate.previousIndex + 1)
4255
+ ];
4256
+ } else {
4257
+ newState = [
4258
+ ...newState.slice(0, listUpdate.previousIndex),
4259
+ ...newState.slice(
4260
+ listUpdate.previousIndex + 1,
4261
+ listUpdate.index + 1
4262
+ ),
4263
+ lsonToJson(listUpdate.item),
4264
+ ...newState.slice(listUpdate.index + 1)
4265
+ ];
4266
+ }
4267
+ }
4268
+ }
4269
+ return newState;
4270
+ }
4271
+ case "LiveMap": {
4272
+ if (state === null || typeof state !== "object" || Array.isArray(state)) {
4273
+ throw new Error(
4274
+ "Internal: received update on LiveMap but state was not an object"
4275
+ );
4276
+ }
4277
+ const newState = Object.assign({}, state);
4278
+ for (const key in update.updates) {
4279
+ if (((_c = update.updates[key]) == null ? void 0 : _c.type) === "update") {
4280
+ const value = update.node.get(key);
4281
+ if (value !== void 0) {
4282
+ newState[key] = lsonToJson(value);
4283
+ }
4284
+ } else if (((_d = update.updates[key]) == null ? void 0 : _d.type) === "delete") {
4285
+ delete newState[key];
4286
+ }
4287
+ }
4288
+ return newState;
4289
+ }
4290
+ }
4291
+ }
4292
+ if (Array.isArray(state)) {
4293
+ const newArray = [...state];
4294
+ newArray[pathItem] = legacy_patchImmutableNode(
4295
+ state[pathItem],
4296
+ path,
4297
+ update
4298
+ );
4299
+ return newArray;
4300
+ } else if (state !== null && typeof state === "object") {
4301
+ const node = state[pathItem];
4302
+ if (node === void 0) {
4303
+ return state;
4304
+ } else {
4305
+ return __spreadProps(__spreadValues({}, state), {
4306
+ [pathItem]: legacy_patchImmutableNode(node, path, update)
4307
+ });
4308
+ }
4309
+ } else {
4310
+ return state;
4311
+ }
4312
+ }
4313
+
4269
4314
  // src/shallow.ts
4270
4315
  function shallowArray(xs, ys) {
4271
4316
  if (xs.length !== ys.length) {