@liveblocks/core 0.19.3-beta4 → 0.19.3

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 CHANGED
@@ -633,6 +633,48 @@ declare type OthersEvent<TPresence extends JsonObject, TUserMeta extends BaseUse
633
633
  type: "reset";
634
634
  };
635
635
 
636
+ declare type JsonTreeNode = {
637
+ readonly type: "Json";
638
+ readonly id: string;
639
+ readonly key: string;
640
+ readonly payload: Json;
641
+ };
642
+ declare type LiveTreeNode<TName extends `Live${string}` = `Live${string}`> = {
643
+ readonly type: TName;
644
+ readonly id: string;
645
+ readonly key: string;
646
+ readonly payload: LsonTreeNode[];
647
+ };
648
+ declare type LsonTreeNode = LiveTreeNode | JsonTreeNode;
649
+ declare type UserTreeNode = {
650
+ readonly type: "User";
651
+ readonly id: string;
652
+ readonly key: string;
653
+ readonly payload: {
654
+ readonly connectionId: number;
655
+ readonly id?: string;
656
+ readonly info?: Json;
657
+ readonly presence: JsonObject;
658
+ readonly isReadOnly: boolean;
659
+ };
660
+ };
661
+ declare type TreeNode = LsonTreeNode | UserTreeNode;
662
+
663
+ type DevToolsTreeNode_JsonTreeNode = JsonTreeNode;
664
+ type DevToolsTreeNode_LiveTreeNode<TName extends `Live${string}` = `Live${string}`> = LiveTreeNode<TName>;
665
+ type DevToolsTreeNode_LsonTreeNode = LsonTreeNode;
666
+ type DevToolsTreeNode_UserTreeNode = UserTreeNode;
667
+ type DevToolsTreeNode_TreeNode = TreeNode;
668
+ declare namespace DevToolsTreeNode {
669
+ export {
670
+ DevToolsTreeNode_JsonTreeNode as JsonTreeNode,
671
+ DevToolsTreeNode_LiveTreeNode as LiveTreeNode,
672
+ DevToolsTreeNode_LsonTreeNode as LsonTreeNode,
673
+ DevToolsTreeNode_UserTreeNode as UserTreeNode,
674
+ DevToolsTreeNode_TreeNode as TreeNode,
675
+ };
676
+ }
677
+
636
678
  declare type CustomEvent<TRoomEvent extends Json> = {
637
679
  connectionId: number;
638
680
  event: TRoomEvent;
@@ -863,7 +905,16 @@ declare type Room<TPresence extends JsonObject, TStorage extends LsonObject, TUs
863
905
  * @example
864
906
  * room.subscribe("storage-status", (status) => {
865
907
  * switch(status) {
866
- * case
908
+ * case "not-loaded":
909
+ * break;
910
+ * case "loading":
911
+ * break;
912
+ * case "synchronizing":
913
+ * break;
914
+ * case "synchronized":
915
+ * break;
916
+ * default:
917
+ * break;
867
918
  * }
868
919
  * });
869
920
  */
@@ -983,6 +1034,11 @@ declare type Room<TPresence extends JsonObject, TStorage extends LsonObject, TUs
983
1034
  batch<T>(fn: () => T): T;
984
1035
  /**
985
1036
  * Get the storage status.
1037
+ *
1038
+ * - `not-loaded`: Initial state when entering the room.
1039
+ * - `loading`: Once the storage has been requested via room.getStorage().
1040
+ * - `synchronizing`: When some local updates have not been acknowledged by Liveblocks servers.
1041
+ * - `synchronized`: Storage is in sync with Liveblocks servers.
986
1042
  */
987
1043
  getStorageStatus(): StorageStatus;
988
1044
  /**
@@ -1392,6 +1448,115 @@ declare enum WebsocketCloseCodes {
1392
1448
  CLOSE_WITHOUT_RETRY = 4999
1393
1449
  }
1394
1450
 
1451
+ /**
1452
+ * Definition of all messages the Panel can send to the Client.
1453
+ */
1454
+ declare type PanelToClientMessage =
1455
+ /**
1456
+ * Initial message from the panel to the client, used for two purposes.
1457
+ * 1. First, it’s eavesdropped by the background script, which uses this
1458
+ * message to register a "port", which sets up a channel for two-way
1459
+ * communication between panel and client for the remainder of the time.
1460
+ * 2. It signifies to the client that the devpanel is listening.
1461
+ */
1462
+ {
1463
+ msg: "connect";
1464
+ }
1465
+ /**
1466
+ * Expresses to the client that the devtool is interested in
1467
+ * receiving the "sync stream" for the room. The sync stream
1468
+ * that follows is an initial "full sync", followed by many
1469
+ * "partial" syncs, happening for every update.
1470
+ */
1471
+ | {
1472
+ msg: "room::subscribe";
1473
+ roomId: string;
1474
+ }
1475
+ /**
1476
+ * Expresses to the client that the devtool no longer is
1477
+ * interested in the "sync stream" for a room, for example,
1478
+ * because the devtools panel is closed, or if it switched to
1479
+ * a different room.
1480
+ */
1481
+ | {
1482
+ msg: "room::unsubscribe";
1483
+ roomId: string;
1484
+ };
1485
+ /**
1486
+ * Definition of all messages the Client can send to the Panel.
1487
+ */
1488
+ declare type ClientToPanelMessage =
1489
+ /**
1490
+ * Initial message sent by the client to test if a dev panel is listening.
1491
+ * This is necessary in cases where the dev panel is already opened and
1492
+ * listened, before the client is loaded. If the panel receives this message,
1493
+ * it will replay its initial "connect" message, which triggers the loading
1494
+ * of the two-way connection.
1495
+ */
1496
+ {
1497
+ msg: "wake-up-devtools";
1498
+ }
1499
+ /**
1500
+ * Sent when a new room is available for the dev panel to track and watch.
1501
+ * Sent by the client as soon as the room is attempted to be entered. This
1502
+ * happens _before_ the actual connection to the room server is established,
1503
+ * meaning the room is visible to the devtools even while it is connecting.
1504
+ */
1505
+ | {
1506
+ msg: "room::available";
1507
+ roomId: string;
1508
+ clientVersion: string;
1509
+ }
1510
+ /**
1511
+ * Sent when a room is left and the client loses track of the room instance.
1512
+ */
1513
+ | {
1514
+ msg: "room::unavailable";
1515
+ roomId: string;
1516
+ }
1517
+ /**
1518
+ * Sent initially, to synchronize the entire current state of the room.
1519
+ */
1520
+ | {
1521
+ msg: "room::sync::full";
1522
+ roomId: string;
1523
+ status: ConnectionState;
1524
+ storage: readonly LsonTreeNode[] | null;
1525
+ me: UserTreeNode | null;
1526
+ others: readonly UserTreeNode[];
1527
+ }
1528
+ /**
1529
+ * Sent whenever something about the internals of a room changes.
1530
+ */
1531
+ | {
1532
+ msg: "room::sync::partial";
1533
+ roomId: string;
1534
+ status?: ConnectionState;
1535
+ storage?: readonly LsonTreeNode[];
1536
+ me?: UserTreeNode;
1537
+ others?: readonly UserTreeNode[];
1538
+ };
1539
+ declare type FullPanelToClientMessage = PanelToClientMessage & {
1540
+ source: "liveblocks-devtools-panel";
1541
+ tabId: number;
1542
+ };
1543
+ declare type FullClientToPanelMessage = ClientToPanelMessage & {
1544
+ source: "liveblocks-devtools-client";
1545
+ };
1546
+
1547
+ type protocol_PanelToClientMessage = PanelToClientMessage;
1548
+ type protocol_ClientToPanelMessage = ClientToPanelMessage;
1549
+ type protocol_FullPanelToClientMessage = FullPanelToClientMessage;
1550
+ type protocol_FullClientToPanelMessage = FullClientToPanelMessage;
1551
+ declare namespace protocol {
1552
+ export {
1553
+ protocol_PanelToClientMessage as PanelToClientMessage,
1554
+ protocol_ClientToPanelMessage as ClientToPanelMessage,
1555
+ protocol_FullPanelToClientMessage as FullPanelToClientMessage,
1556
+ protocol_FullClientToPanelMessage as FullClientToPanelMessage,
1557
+ };
1558
+ }
1559
+
1395
1560
  /**
1396
1561
  * PRIVATE / INTERNAL APIS
1397
1562
  * -----------------------
@@ -1417,4 +1582,4 @@ declare type EnsureJson<T> = [
1417
1582
  [K in keyof T]: EnsureJson<T[K]>;
1418
1583
  };
1419
1584
 
1420
- export { AppOnlyAuthToken, AuthToken, BaseUserMeta, BroadcastEventClientMsg, BroadcastOptions, BroadcastedEventServerMsg, Client, ClientMsg, ClientMsgCode, CrdtType, CreateChildOp, CreateListOp, CreateMapOp, CreateObjectOp, CreateOp, CreateRegisterOp, CreateRootObjectOp, DeleteCrdtOp, DeleteObjectKeyOp, EnsureJson, FetchStorageClientMsg, History, IdTuple, Immutable, InitialDocumentStateServerMsg, Json, JsonObject, LiveList, LiveMap, LiveNode, LiveObject, LiveStructure, Lson, LsonObject, NodeMap, Op, OpCode, Others, ParentToChildNodeMap, Resolve, Room, RoomAuthToken, RoomInitializers, RoomStateServerMsg, SerializedChild, SerializedCrdt, SerializedList, SerializedMap, SerializedObject, SerializedRegister, SerializedRootObject, ServerMsg, ServerMsgCode, SetParentKeyOp, StorageUpdate, ToImmutable, ToJson, UpdateObjectOp, UpdatePresenceClientMsg, UpdatePresenceServerMsg, UpdateStorageClientMsg, UpdateStorageServerMsg, User, UserJoinServerMsg, UserLeftServerMsg, WebsocketCloseCodes, asArrayWithLegacyMethods, 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 };
1585
+ export { AppOnlyAuthToken, AuthToken, BaseUserMeta, BroadcastEventClientMsg, BroadcastOptions, BroadcastedEventServerMsg, Client, ClientMsg, ClientMsgCode, ConnectionState, CrdtType, CreateChildOp, CreateListOp, CreateMapOp, CreateObjectOp, CreateOp, CreateRegisterOp, CreateRootObjectOp, DeleteCrdtOp, DeleteObjectKeyOp, DevToolsTreeNode as DevTools, protocol as DevToolsMsg, EnsureJson, FetchStorageClientMsg, History, IdTuple, Immutable, InitialDocumentStateServerMsg, Json, JsonObject, LiveList, LiveMap, LiveNode, LiveObject, LiveStructure, Lson, LsonObject, NodeMap, Op, OpCode, Others, ParentToChildNodeMap, Resolve, Room, RoomAuthToken, RoomInitializers, RoomStateServerMsg, SerializedChild, SerializedCrdt, SerializedList, SerializedMap, SerializedObject, SerializedRegister, SerializedRootObject, ServerMsg, ServerMsgCode, SetParentKeyOp, StorageUpdate, ToImmutable, ToJson, UpdateObjectOp, UpdatePresenceClientMsg, UpdatePresenceServerMsg, UpdateStorageClientMsg, UpdateStorageServerMsg, User, UserJoinServerMsg, UserLeftServerMsg, WebsocketCloseCodes, asArrayWithLegacyMethods, 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 };
package/dist/index.js CHANGED
@@ -50,6 +50,213 @@ var __async = (__this, __arguments, generator) => {
50
50
  });
51
51
  };
52
52
 
53
+ // src/lib/EventSource.ts
54
+ function makeEventSource() {
55
+ const _onetimeObservers = /* @__PURE__ */ new Set();
56
+ const _observers = /* @__PURE__ */ new Set();
57
+ function subscribe(callback) {
58
+ _observers.add(callback);
59
+ return () => _observers.delete(callback);
60
+ }
61
+ function subscribeOnce(callback) {
62
+ _onetimeObservers.add(callback);
63
+ return () => _onetimeObservers.delete(callback);
64
+ }
65
+ function notify(event) {
66
+ _onetimeObservers.forEach((callback) => callback(event));
67
+ _onetimeObservers.clear();
68
+ _observers.forEach((callback) => callback(event));
69
+ }
70
+ function clear() {
71
+ _onetimeObservers.clear();
72
+ _observers.clear();
73
+ }
74
+ return {
75
+ notify,
76
+ subscribe,
77
+ subscribeOnce,
78
+ clear,
79
+ observable: {
80
+ subscribe,
81
+ subscribeOnce
82
+ }
83
+ };
84
+ }
85
+
86
+ // src/devtools/bridge.ts
87
+ var _bridgeActive = false;
88
+ function activateBridge(allowed) {
89
+ _bridgeActive = allowed;
90
+ }
91
+ function sendToPanel(message, options) {
92
+ if (process.env.NODE_ENV === "production" || typeof window === "undefined") {
93
+ return;
94
+ }
95
+ const fullMsg = __spreadProps(__spreadValues({}, message), {
96
+ source: "liveblocks-devtools-client"
97
+ });
98
+ if (!((options == null ? void 0 : options.force) || _bridgeActive)) {
99
+ return;
100
+ }
101
+ window.postMessage(fullMsg, "*");
102
+ }
103
+ var eventSource = makeEventSource();
104
+ if (process.env.NODE_ENV !== "production" && typeof window !== "undefined") {
105
+ window.addEventListener("message", (event) => {
106
+ var _a;
107
+ if (event.source === window && ((_a = event.data) == null ? void 0 : _a.source) === "liveblocks-devtools-panel") {
108
+ eventSource.notify(event.data);
109
+ } else {
110
+ }
111
+ });
112
+ }
113
+ var onMessageFromPanel = eventSource.observable;
114
+
115
+ // src/devtools/index.ts
116
+ var VERSION = true ? "0.19.3" : "dev";
117
+ var _devtoolsSetupHasRun = false;
118
+ function setupDevTools(getAllRooms) {
119
+ if (process.env.NODE_ENV === "production" || typeof window === "undefined") {
120
+ return;
121
+ }
122
+ if (_devtoolsSetupHasRun) {
123
+ return;
124
+ }
125
+ _devtoolsSetupHasRun = true;
126
+ onMessageFromPanel.subscribe((msg) => {
127
+ switch (msg.msg) {
128
+ case "connect": {
129
+ activateBridge(true);
130
+ for (const roomId of getAllRooms()) {
131
+ sendToPanel({
132
+ msg: "room::available",
133
+ roomId,
134
+ clientVersion: VERSION
135
+ });
136
+ }
137
+ break;
138
+ }
139
+ }
140
+ });
141
+ sendToPanel({ msg: "wake-up-devtools" }, { force: true });
142
+ }
143
+ var unsubsByRoomId = /* @__PURE__ */ new Map();
144
+ function stopSyncStream(roomId) {
145
+ var _a;
146
+ const unsubs = (_a = unsubsByRoomId.get(roomId)) != null ? _a : [];
147
+ unsubsByRoomId.delete(roomId);
148
+ for (const unsub of unsubs) {
149
+ unsub();
150
+ }
151
+ }
152
+ function startSyncStream(room) {
153
+ stopSyncStream(room.id);
154
+ fullSync(room);
155
+ unsubsByRoomId.set(room.id, [
156
+ room.events.connection.subscribe(() => partialSyncConnection(room)),
157
+ room.events.storageDidLoad.subscribeOnce(() => partialSyncStorage(room)),
158
+ room.events.storage.subscribe(() => partialSyncStorage(room)),
159
+ room.events.me.subscribe(() => partialSyncMe(room)),
160
+ room.events.others.subscribe(() => partialSyncOthers(room))
161
+ ]);
162
+ }
163
+ function partialSyncConnection(room) {
164
+ sendToPanel({
165
+ msg: "room::sync::partial",
166
+ roomId: room.id,
167
+ status: room.getConnectionState()
168
+ });
169
+ }
170
+ function partialSyncStorage(room) {
171
+ const root = room.getStorageSnapshot();
172
+ if (root) {
173
+ sendToPanel({
174
+ msg: "room::sync::partial",
175
+ roomId: room.id,
176
+ storage: root.toTreeNode("root").payload
177
+ });
178
+ }
179
+ }
180
+ function partialSyncMe(room) {
181
+ const me = room.getSelf_forDevTools();
182
+ if (me) {
183
+ sendToPanel({
184
+ msg: "room::sync::partial",
185
+ roomId: room.id,
186
+ me
187
+ });
188
+ }
189
+ }
190
+ function partialSyncOthers(room) {
191
+ const others = room.getOthers_forDevTools();
192
+ if (others) {
193
+ sendToPanel({
194
+ msg: "room::sync::partial",
195
+ roomId: room.id,
196
+ others
197
+ });
198
+ }
199
+ }
200
+ function fullSync(room) {
201
+ var _a;
202
+ const root = room.getStorageSnapshot();
203
+ const me = room.getSelf_forDevTools();
204
+ const others = room.getOthers_forDevTools();
205
+ sendToPanel({
206
+ msg: "room::sync::full",
207
+ roomId: room.id,
208
+ status: room.getConnectionState(),
209
+ storage: (_a = root == null ? void 0 : root.toTreeNode("root").payload) != null ? _a : null,
210
+ me,
211
+ others
212
+ });
213
+ }
214
+ var roomChannelListeners = /* @__PURE__ */ new Map();
215
+ function stopRoomChannelListener(roomId) {
216
+ const listener = roomChannelListeners.get(roomId);
217
+ roomChannelListeners.delete(roomId);
218
+ if (listener) {
219
+ listener();
220
+ }
221
+ }
222
+ function linkDevTools(roomId, room) {
223
+ if (process.env.NODE_ENV === "production" || typeof window === "undefined") {
224
+ return;
225
+ }
226
+ sendToPanel({ msg: "room::available", roomId, clientVersion: VERSION });
227
+ stopRoomChannelListener(roomId);
228
+ roomChannelListeners.set(
229
+ roomId,
230
+ onMessageFromPanel.subscribe((msg) => {
231
+ switch (msg.msg) {
232
+ case "room::subscribe": {
233
+ if (msg.roomId === roomId) {
234
+ startSyncStream(room);
235
+ }
236
+ break;
237
+ }
238
+ case "room::unsubscribe": {
239
+ if (msg.roomId === roomId) {
240
+ stopSyncStream(roomId);
241
+ }
242
+ break;
243
+ }
244
+ }
245
+ })
246
+ );
247
+ }
248
+ function unlinkDevTools(roomId) {
249
+ if (process.env.NODE_ENV === "production" || typeof window === "undefined") {
250
+ return;
251
+ }
252
+ stopSyncStream(roomId);
253
+ stopRoomChannelListener(roomId);
254
+ sendToPanel({
255
+ msg: "room::unavailable",
256
+ roomId
257
+ });
258
+ }
259
+
53
260
  // src/lib/fancy-console.ts
54
261
  var badge = "background:radial-gradient(106.94% 108.33% at -10% -5%,#ff1aa3 0,#ff881a 100%);border-radius:3px;color:#fff;padding:2px 5px;font-family:sans-serif;font-weight:600";
55
262
  var bold = "font-weight:600";
@@ -257,13 +464,21 @@ var AbstractCrdt = class {
257
464
  this.__pool = void 0;
258
465
  }
259
466
  invalidate() {
260
- if (this._cachedImmutable !== void 0) {
467
+ if (this._cachedImmutable !== void 0 || this._cachedTreeNode !== void 0) {
261
468
  this._cachedImmutable = void 0;
469
+ this._cachedTreeNode = void 0;
262
470
  if (this.parent.type === "HasParent") {
263
471
  this.parent.node.invalidate();
264
472
  }
265
473
  }
266
474
  }
475
+ toTreeNode(key) {
476
+ if (this._cachedTreeNode === void 0 || this._cachedTreeNodeKey !== key) {
477
+ this._cachedTreeNodeKey = key;
478
+ this._cachedTreeNode = this._toTreeNode(key);
479
+ }
480
+ return this._cachedTreeNode;
481
+ }
267
482
  toImmutable() {
268
483
  if (this._cachedImmutable === void 0) {
269
484
  this._cachedImmutable = this._toImmutable();
@@ -337,6 +552,16 @@ function isChildCrdt(crdt) {
337
552
  return crdt.parentId !== void 0 && crdt.parentKey !== void 0;
338
553
  }
339
554
 
555
+ // src/lib/nanoid.ts
556
+ function nanoid(length = 7) {
557
+ const alphabet = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789,./;[]~!@#$%&*()_+=-";
558
+ const len = alphabet.length;
559
+ return Array.from(
560
+ { length },
561
+ () => alphabet.charAt(Math.floor(Math.random() * len))
562
+ ).join("");
563
+ }
564
+
340
565
  // src/lib/position.ts
341
566
  var min = 32;
342
567
  var max = 126;
@@ -492,6 +717,15 @@ var LiveRegister = class extends AbstractCrdt {
492
717
  _apply(op, isLocal) {
493
718
  return super._apply(op, isLocal);
494
719
  }
720
+ _toTreeNode(key) {
721
+ var _a;
722
+ return {
723
+ type: "Json",
724
+ id: (_a = this._id) != null ? _a : nanoid(),
725
+ key,
726
+ payload: this._data
727
+ };
728
+ }
495
729
  _toImmutable() {
496
730
  return this._data;
497
731
  }
@@ -1315,6 +1549,17 @@ var LiveList = class extends AbstractCrdt {
1315
1549
  );
1316
1550
  this._items[index]._setParentLink(this, shiftedPosition);
1317
1551
  }
1552
+ _toTreeNode(key) {
1553
+ var _a;
1554
+ return {
1555
+ type: "LiveList",
1556
+ id: (_a = this._id) != null ? _a : nanoid(),
1557
+ key,
1558
+ payload: this._items.map(
1559
+ (item, index) => item.toTreeNode(index.toString())
1560
+ )
1561
+ };
1562
+ }
1318
1563
  toImmutable() {
1319
1564
  return super.toImmutable();
1320
1565
  }
@@ -1656,6 +1901,17 @@ var LiveMap = class extends AbstractCrdt {
1656
1901
  callback(entry[1], entry[0], this);
1657
1902
  }
1658
1903
  }
1904
+ _toTreeNode(key) {
1905
+ var _a;
1906
+ return {
1907
+ type: "LiveMap",
1908
+ id: (_a = this._id) != null ? _a : nanoid(),
1909
+ key,
1910
+ payload: Array.from(this._map.entries()).map(
1911
+ ([key2, val]) => val.toTreeNode(key2)
1912
+ )
1913
+ };
1914
+ }
1659
1915
  toImmutable() {
1660
1916
  return super.toImmutable();
1661
1917
  }
@@ -2087,6 +2343,21 @@ var LiveObject = class extends AbstractCrdt {
2087
2343
  toImmutable() {
2088
2344
  return super.toImmutable();
2089
2345
  }
2346
+ toTreeNode(key) {
2347
+ return super.toTreeNode(key);
2348
+ }
2349
+ _toTreeNode(key) {
2350
+ var _a;
2351
+ const nodeId = (_a = this._id) != null ? _a : nanoid();
2352
+ return {
2353
+ type: "LiveObject",
2354
+ id: nodeId,
2355
+ key,
2356
+ payload: Array.from(this._map.entries()).map(
2357
+ ([key2, value]) => isLiveNode(value) ? value.toTreeNode(key2) : { type: "Json", id: `${nodeId}:${key2}`, key: key2, payload: value }
2358
+ )
2359
+ };
2360
+ }
2090
2361
  _toImmutable() {
2091
2362
  const result = {};
2092
2363
  for (const [key, val] of this._map) {
@@ -2340,39 +2611,6 @@ function findNonSerializableValue(value, path = "") {
2340
2611
  return false;
2341
2612
  }
2342
2613
 
2343
- // src/lib/EventSource.ts
2344
- function makeEventSource() {
2345
- const _onetimeObservers = /* @__PURE__ */ new Set();
2346
- const _observers = /* @__PURE__ */ new Set();
2347
- function subscribe(callback) {
2348
- _observers.add(callback);
2349
- return () => _observers.delete(callback);
2350
- }
2351
- function subscribeOnce(callback) {
2352
- _onetimeObservers.add(callback);
2353
- return () => _onetimeObservers.delete(callback);
2354
- }
2355
- function notify(event) {
2356
- _onetimeObservers.forEach((callback) => callback(event));
2357
- _onetimeObservers.clear();
2358
- _observers.forEach((callback) => callback(event));
2359
- }
2360
- function clear() {
2361
- _onetimeObservers.clear();
2362
- _observers.clear();
2363
- }
2364
- return {
2365
- notify,
2366
- subscribe,
2367
- subscribeOnce,
2368
- clear,
2369
- observable: {
2370
- subscribe,
2371
- subscribeOnce
2372
- }
2373
- };
2374
- }
2375
-
2376
2614
  // src/lib/Json.ts
2377
2615
  function isJsonScalar(data) {
2378
2616
  return data === null || typeof data === "string" || typeof data === "number" || typeof data === "boolean";
@@ -2659,7 +2897,7 @@ var WebsocketCloseCodes = /* @__PURE__ */ ((WebsocketCloseCodes2) => {
2659
2897
 
2660
2898
  // src/room.ts
2661
2899
  function isRoomEventName(value) {
2662
- return value === "my-presence" || value === "others" || value === "event" || value === "error" || value === "connection" || value === "history" || value === "pending-storage-modifications";
2900
+ return value === "my-presence" || value === "others" || value === "event" || value === "error" || value === "connection" || value === "history" || value === "storage-status";
2663
2901
  }
2664
2902
  var BACKOFF_RETRY_DELAYS = [250, 500, 1e3, 2e3, 4e3, 8e3, 1e4];
2665
2903
  var BACKOFF_RETRY_DELAYS_SLOW = [2e3, 3e4, 6e4, 3e5];
@@ -2675,6 +2913,14 @@ function log(..._params) {
2675
2913
  function isConnectionSelfAware(connection) {
2676
2914
  return connection.state === "open" || connection.state === "connecting";
2677
2915
  }
2916
+ function userToTreeNode(key, user) {
2917
+ return {
2918
+ type: "User",
2919
+ id: `${user.connectionId}`,
2920
+ key,
2921
+ payload: user
2922
+ };
2923
+ }
2678
2924
  function makeStateMachine(state, config, mockedEffects) {
2679
2925
  var _a;
2680
2926
  const doNotBatchUpdates = (cb) => cb();
@@ -2782,6 +3028,10 @@ function makeStateMachine(state, config, mockedEffects) {
2782
3028
  isReadOnly: conn.isReadOnly
2783
3029
  } : null
2784
3030
  );
3031
+ const selfAsTreeNode = new DerivedRef(
3032
+ self,
3033
+ (me) => me !== null ? userToTreeNode("Me", me) : null
3034
+ );
2785
3035
  function createOrUpdateRootFromMessage(message, batchedUpdatesWrapper) {
2786
3036
  if (message.items.length === 0) {
2787
3037
  throw new Error("Internal error: cannot load storage without items");
@@ -2918,7 +3168,7 @@ function makeStateMachine(state, config, mockedEffects) {
2918
3168
  if (isLocal) {
2919
3169
  source = 0 /* UNDOREDO_RECONNECT */;
2920
3170
  } else {
2921
- const deleted = state.offlineOperations.delete(nn(op.opId));
3171
+ const deleted = state.unacknowledgedOps.delete(nn(op.opId));
2922
3172
  source = deleted ? 2 /* ACK */ : 1 /* REMOTE */;
2923
3173
  }
2924
3174
  const applyOpResult = applyOp(op, source);
@@ -3297,9 +3547,9 @@ function makeStateMachine(state, config, mockedEffects) {
3297
3547
  break;
3298
3548
  }
3299
3549
  case 200 /* INITIAL_STORAGE_STATE */: {
3300
- const offlineOps = new Map(state.offlineOperations);
3550
+ const unacknowledgedOps = new Map(state.unacknowledgedOps);
3301
3551
  createOrUpdateRootFromMessage(message, doNotBatchUpdates);
3302
- applyAndSendOfflineOps(offlineOps, doNotBatchUpdates);
3552
+ applyAndSendOps(unacknowledgedOps, doNotBatchUpdates);
3303
3553
  if (_getInitialStateResolver !== null) {
3304
3554
  _getInitialStateResolver();
3305
3555
  }
@@ -3434,7 +3684,7 @@ function makeStateMachine(state, config, mockedEffects) {
3434
3684
  clearInterval(state.intervalHandles.heartbeat);
3435
3685
  connect();
3436
3686
  }
3437
- function applyAndSendOfflineOps(offlineOps, batchedUpdatesWrapper) {
3687
+ function applyAndSendOps(offlineOps, batchedUpdatesWrapper) {
3438
3688
  if (offlineOps.size === 0) {
3439
3689
  return;
3440
3690
  }
@@ -3452,7 +3702,7 @@ function makeStateMachine(state, config, mockedEffects) {
3452
3702
  const storageOps = state.buffer.storageOperations;
3453
3703
  if (storageOps.length > 0) {
3454
3704
  storageOps.forEach((op) => {
3455
- state.offlineOperations.set(nn(op.opId), op);
3705
+ state.unacknowledgedOps.set(nn(op.opId), op);
3456
3706
  });
3457
3707
  notifyStorageStatus();
3458
3708
  }
@@ -3527,7 +3777,7 @@ function makeStateMachine(state, config, mockedEffects) {
3527
3777
  clearInterval(state.intervalHandles.heartbeat);
3528
3778
  state.others.clearOthers();
3529
3779
  notify({ others: [{ type: "reset" }] }, doNotBatchUpdates);
3530
- Object.values(eventHub).forEach((eventSource) => eventSource.clear());
3780
+ Object.values(eventHub).forEach((eventSource2) => eventSource2.clear());
3531
3781
  });
3532
3782
  }
3533
3783
  function getPresence() {
@@ -3691,13 +3941,13 @@ function makeStateMachine(state, config, mockedEffects) {
3691
3941
  onClose(event);
3692
3942
  }
3693
3943
  function getStorageStatus() {
3694
- if (state.root !== void 0) {
3695
- return state.offlineOperations.size === 0 ? "synchronized" : "synchronizing";
3944
+ if (_getInitialStatePromise === null) {
3945
+ return "not-loaded";
3696
3946
  }
3697
- if (_getInitialStatePromise !== null) {
3947
+ if (state.root === void 0) {
3698
3948
  return "loading";
3699
3949
  }
3700
- return "not-loaded";
3950
+ return state.unacknowledgedOps.size === 0 ? "synchronized" : "synchronizing";
3701
3951
  }
3702
3952
  let _lastStorageStatus = getStorageStatus();
3703
3953
  function notifyStorageStatus() {
@@ -3749,11 +3999,17 @@ function makeStateMachine(state, config, mockedEffects) {
3749
3999
  isSelfAware: () => isConnectionSelfAware(state.connection.current),
3750
4000
  getSelf: () => self.current,
3751
4001
  getPresence,
3752
- getOthers
4002
+ getOthers,
4003
+ getSelf_forDevTools: () => selfAsTreeNode.current,
4004
+ getOthers_forDevTools: () => state.others_forDevTools.current
3753
4005
  };
3754
4006
  }
3755
4007
  function defaultState(initialPresence, initialStorage) {
3756
4008
  const others = new OthersRef();
4009
+ const others_forDevTools = new DerivedRef(
4010
+ others,
4011
+ (others2) => others2.map((other, index) => userToTreeNode(`Other ${index}`, other))
4012
+ );
3757
4013
  const connection = new ValueRef({ state: "closed" });
3758
4014
  return {
3759
4015
  token: null,
@@ -3780,6 +4036,7 @@ function defaultState(initialPresence, initialStorage) {
3780
4036
  connection,
3781
4037
  me: new MeRef(initialPresence),
3782
4038
  others,
4039
+ others_forDevTools,
3783
4040
  initialStorage,
3784
4041
  idFactory: null,
3785
4042
  clock: 0,
@@ -3790,7 +4047,7 @@ function defaultState(initialPresence, initialStorage) {
3790
4047
  redoStack: [],
3791
4048
  pausedHistory: null,
3792
4049
  activeBatch: null,
3793
- offlineOperations: /* @__PURE__ */ new Map()
4050
+ unacknowledgedOps: /* @__PURE__ */ new Map()
3794
4051
  };
3795
4052
  }
3796
4053
  function createRoom(options, config) {
@@ -3830,7 +4087,9 @@ function createRoom(options, config) {
3830
4087
  __INTERNAL_DO_NOT_USE: {
3831
4088
  simulateCloseWebsocket: machine.simulateSocketClose,
3832
4089
  simulateSendCloseEvent: machine.simulateSendCloseEvent
3833
- }
4090
+ },
4091
+ getSelf_forDevTools: machine.getSelf_forDevTools,
4092
+ getOthers_forDevTools: machine.getOthers_forDevTools
3834
4093
  };
3835
4094
  return {
3836
4095
  connect: machine.connect,
@@ -3855,7 +4114,7 @@ function prepareCreateWebSocket(liveblocksServer, WebSocketPolyfill) {
3855
4114
  const ws = WebSocketPolyfill || WebSocket;
3856
4115
  return (token) => {
3857
4116
  return new ws(
3858
- `${liveblocksServer}/?token=${token}&version=${true ? "0.19.3-beta4" : "dev"}`
4117
+ `${liveblocksServer}/?token=${token}&version=${true ? "0.19.3" : "dev"}`
3859
4118
  );
3860
4119
  };
3861
4120
  }
@@ -3978,6 +4237,8 @@ function createClient(options) {
3978
4237
  roomId,
3979
4238
  internalRoom
3980
4239
  );
4240
+ setupDevTools(() => Array.from(rooms.keys()));
4241
+ linkDevTools(roomId, internalRoom.room);
3981
4242
  if (shouldConnect) {
3982
4243
  if (typeof atob === "undefined") {
3983
4244
  if (((_b = clientOptions.polyfills) == null ? void 0 : _b.atob) === void 0) {
@@ -3992,6 +4253,7 @@ function createClient(options) {
3992
4253
  return internalRoom.room;
3993
4254
  }
3994
4255
  function leave(roomId) {
4256
+ unlinkDevTools(roomId);
3995
4257
  const room = rooms.get(roomId);
3996
4258
  if (room) {
3997
4259
  room.disconnect();
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@liveblocks/core",
3
- "version": "0.19.3-beta4",
3
+ "version": "0.19.3",
4
4
  "description": "Shared code and foundational internals for Liveblocks",
5
5
  "main": "./dist/index.js",
6
6
  "types": "./dist/index.d.ts",