@pluv/client 2.0.2 → 2.2.0

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.js CHANGED
@@ -78,6 +78,7 @@ var AbstractStorageStore = class {
78
78
 
79
79
  // src/constants.ts
80
80
  var MAX_PRESENCE_SIZE_BYTES = 512;
81
+ var PLUV_PRESENCE_META_KEY = "__pluv";
81
82
 
82
83
  // src/PluvProcedure.ts
83
84
  var PluvProcedure = class _PluvProcedure {
@@ -124,7 +125,7 @@ var CrdtManager = class {
124
125
  this.initialized = false;
125
126
  const { initialStorage = import_crdt.noop.doc({}) } = options;
126
127
  this._docFactory = initialStorage;
127
- this.doc = initialStorage.getEmpty();
128
+ this.doc = this._docFactory.getEmpty();
128
129
  }
129
130
  /**
130
131
  * !HACK
@@ -164,11 +165,7 @@ var CrdtManager = class {
164
165
  if (!updates.length) return this;
165
166
  const initialized = this._docFactory.getInitialized();
166
167
  const reference = initialized.get();
167
- this.doc = this._applyDocUpdates(
168
- this._docFactory.getEmpty(),
169
- updates,
170
- origin
171
- ).rebuildStorage(reference);
168
+ this.doc = this._applyDocUpdates(this.doc, updates, origin).rebuildStorage(reference);
172
169
  this.initialized = true;
173
170
  initialized.destroy();
174
171
  return this;
@@ -228,31 +225,21 @@ var EventNotifier = class {
228
225
  }
229
226
  };
230
227
 
231
- // src/OtherNotifier.ts
228
+ // src/ListenerManager.ts
232
229
  var import_wonka3 = require("wonka");
233
- var OtherNotifier = class {
230
+ var ListenerManager = class {
234
231
  constructor() {
235
- this._subjects = /* @__PURE__ */ new Map();
236
- }
237
- clear() {
238
- this._subjects.forEach((subject) => {
239
- subject.next(null);
240
- });
241
- this._subjects.clear();
242
- }
243
- delete(clientId) {
244
- this.subject(clientId).next(null);
245
- this._subjects.delete(clientId);
246
- }
247
- subject(clientId) {
248
- const subject = this._subjects.get(clientId);
249
- if (subject) return subject;
250
- const newSubject = (0, import_wonka3.makeSubject)();
251
- this._subjects.set(clientId, newSubject);
252
- return newSubject;
232
+ this.subjects = {
233
+ close: (0, import_wonka3.makeSubject)(),
234
+ error: (0, import_wonka3.makeSubject)(),
235
+ message: (0, import_wonka3.makeSubject)(),
236
+ open: (0, import_wonka3.makeSubject)()
237
+ };
253
238
  }
254
- subscribe(clientId, callback) {
255
- const source = this.subject(clientId).source;
239
+ subscribe(kind, callback) {
240
+ var _a;
241
+ const source = (_a = this.subjects[kind]) == null ? void 0 : _a.source;
242
+ if (!source) return () => void 0;
256
243
  return (0, import_wonka3.subscribe)(callback)(source).unsubscribe;
257
244
  }
258
245
  };
@@ -473,6 +460,9 @@ var UsersManager = class {
473
460
  );
474
461
  const presence = __spreadValues(__spreadValues(__spreadValues({}, this.initialPresence), cleanedPresence), cleanedPatch);
475
462
  const validated = this._presence ? this._presence.parse(presence) : presence;
463
+ if (!!presence[PLUV_PRESENCE_META_KEY]) {
464
+ validated[PLUV_PRESENCE_META_KEY] = presence[PLUV_PRESENCE_META_KEY];
465
+ }
476
466
  this._others.set(clientId, __spreadProps(__spreadValues({}, other), { presence: validated }));
477
467
  return validated;
478
468
  }
@@ -550,6 +540,43 @@ var UsersManager = class {
550
540
  }
551
541
  };
552
542
 
543
+ // src/UsersNotifier.ts
544
+ var import_wonka5 = require("wonka");
545
+ var UsersNotifier = class {
546
+ constructor() {
547
+ this.others = (0, import_wonka5.makeSubject)();
548
+ this._otherSubjects = /* @__PURE__ */ new Map();
549
+ }
550
+ clear() {
551
+ this._otherSubjects.forEach((subject) => {
552
+ subject.next(null);
553
+ });
554
+ this._otherSubjects.clear();
555
+ }
556
+ delete(clientId) {
557
+ this.other(clientId).next(null);
558
+ this._otherSubjects.delete(clientId);
559
+ }
560
+ other(clientId) {
561
+ const subject = this._otherSubjects.get(clientId);
562
+ if (subject) return subject;
563
+ const newSubject = (0, import_wonka5.makeSubject)();
564
+ this._otherSubjects.set(clientId, newSubject);
565
+ return newSubject;
566
+ }
567
+ subscribeOther(clientId, callback) {
568
+ const source = this.other(clientId).source;
569
+ const subscription = (0, import_wonka5.subscribe)(callback)(source);
570
+ return subscription.unsubscribe;
571
+ }
572
+ subscribeOthers(callback) {
573
+ const subscription = (0, import_wonka5.subscribe)(
574
+ ({ others, event }) => callback(others, event)
575
+ )(this.others.source);
576
+ return subscription.unsubscribe;
577
+ }
578
+ };
579
+
553
580
  // src/PluvRoom.ts
554
581
  var ADD_TO_STORAGE_STATE_DEBOUNCE_MS = 1e3;
555
582
  var HEARTBEAT_INTERVAL_MS = 1e4;
@@ -569,7 +596,7 @@ var PluvRoom = class {
569
596
  this._intervals = {
570
597
  heartbeat: null
571
598
  };
572
- this._otherNotifier = new OtherNotifier();
599
+ this._listenerManager = new ListenerManager();
573
600
  this._publicKey = null;
574
601
  this._stateNotifier = new StateNotifier();
575
602
  this._subscriptions = {
@@ -579,6 +606,7 @@ var PluvRoom = class {
579
606
  pong: null,
580
607
  reconnect: null
581
608
  };
609
+ this._usersNotifier = new UsersNotifier();
582
610
  this._lastMetadata = null;
583
611
  this._state = {
584
612
  authorization: {
@@ -587,10 +615,12 @@ var PluvRoom = class {
587
615
  },
588
616
  connection: {
589
617
  attempts: 0,
590
- count: 0,
591
618
  id: null,
592
619
  state: import_types.ConnectionState.Untouched
593
620
  },
621
+ storage: {
622
+ state: import_types.StorageState.Unavailable
623
+ },
594
624
  webSocket: null
595
625
  };
596
626
  this._windowListeners = null;
@@ -633,6 +663,9 @@ var PluvRoom = class {
633
663
  this.canUndo = () => {
634
664
  return !!this._crdtManager.doc.canUndo();
635
665
  };
666
+ /**
667
+ * @deprecated To be removed in v3. Use PluvRoom.subscribe.event instead
668
+ */
636
669
  this.event = new Proxy(
637
670
  (event, callback) => this._eventNotifier.subscribe(event, callback),
638
671
  {
@@ -664,23 +697,80 @@ var PluvRoom = class {
664
697
  if (typeof sharedType === "undefined") return null;
665
698
  return sharedType;
666
699
  };
700
+ this.getStorageLoaded = () => {
701
+ return this._state.storage.state === import_types.StorageState.Offline || this._state.storage.state === import_types.StorageState.Synced;
702
+ };
703
+ /**
704
+ * @deprecated To be removed in v3. Use PluvRoom.subscribe.other instead
705
+ */
667
706
  this.other = (connectionId, callback) => {
668
707
  const clientId = this._usersManager.getClientId(connectionId);
669
708
  if (!clientId) return () => void 0;
670
- return this._otherNotifier.subscribe(clientId, callback);
709
+ return this._usersNotifier.subscribeOther(clientId, callback);
671
710
  };
672
711
  this.redo = () => {
673
712
  this._crdtManager.doc.redo();
674
713
  };
675
- this.storage = (key, fn) => {
676
- return this._crdtNotifier.subscribe(key, fn);
677
- };
678
- this.storageRoot = (fn) => {
679
- return this._crdtNotifier.subcribeRoot(fn);
680
- };
681
- this.subscribe = (name, callback) => {
682
- return this._stateNotifier.subscribe(name, callback);
714
+ /**
715
+ * @deprecated To be removed in v3. Use PluvRoom.subscribe.storage instead
716
+ */
717
+ this.storage = new Proxy(
718
+ (key, callback) => this._crdtNotifier.subscribe(key, callback),
719
+ {
720
+ get: (fn, prop) => {
721
+ if (!!prop) {
722
+ return (callback) => {
723
+ return this._crdtNotifier.subcribeRoot(callback);
724
+ };
725
+ }
726
+ return (callback) => {
727
+ return fn(prop, callback);
728
+ };
729
+ }
730
+ }
731
+ );
732
+ /**
733
+ * @deprecated To be removed in v3. Use PluvRoom.subscribe.storage instead
734
+ * @description Subscribes to the root storage object (serialized)
735
+ */
736
+ this.storageRoot = (callback) => {
737
+ return this._crdtNotifier.subcribeRoot(callback);
683
738
  };
739
+ this.subscribe = new Proxy(
740
+ (name, callback) => this._stateNotifier.subscribe(name, callback),
741
+ {
742
+ get: (fn, prop) => {
743
+ if (prop === "connection") {
744
+ return (callback) => {
745
+ return fn("connection", callback);
746
+ };
747
+ }
748
+ if (prop === "myPresence") {
749
+ return (callback) => {
750
+ return fn("my-presence", callback);
751
+ };
752
+ }
753
+ if (prop === "myself") {
754
+ return (callback) => {
755
+ return fn("myself", callback);
756
+ };
757
+ }
758
+ if (prop === "others") {
759
+ return (callback) => {
760
+ return this._usersNotifier.subscribeOthers(callback);
761
+ };
762
+ }
763
+ if (prop === "storageLoaded") {
764
+ return (callback) => {
765
+ return fn("storage-loaded", callback);
766
+ };
767
+ }
768
+ if (prop === "event") return this.event;
769
+ if (prop === "other") return this.other;
770
+ if (prop === "storage") return this.storage;
771
+ }
772
+ }
773
+ );
684
774
  this.transact = (fn, origin) => {
685
775
  const _origin = origin != null ? origin : this._state.connection.id;
686
776
  if (typeof _origin !== "string") return;
@@ -760,12 +850,18 @@ var PluvRoom = class {
760
850
  });
761
851
  this._crdtManager = new CrdtManager({ initialStorage });
762
852
  }
853
+ /**
854
+ * @deprecated To be removed in v3. Use `getStorageLoaded` instead.
855
+ */
763
856
  get storageLoaded() {
764
- return this._crdtManager.initialized;
857
+ return this.getStorageLoaded();
765
858
  }
766
859
  get webSocket() {
767
860
  return this._state.webSocket;
768
861
  }
862
+ addEventListener(kind, handler) {
863
+ return this._listenerManager.subscribe(kind, handler);
864
+ }
769
865
  connect(...args) {
770
866
  return __async(this, null, function* () {
771
867
  var _a;
@@ -807,6 +903,7 @@ var PluvRoom = class {
807
903
  this._updateState((oldState) => {
808
904
  oldState.connection.attempts = 0;
809
905
  oldState.authorization.token = authToken;
906
+ oldState.storage.state = import_types.StorageState.Loading;
810
907
  oldState.webSocket = webSocket;
811
908
  return oldState;
812
909
  });
@@ -827,6 +924,7 @@ var PluvRoom = class {
827
924
  this._updateState((oldState) => {
828
925
  oldState.authorization.token = null;
829
926
  oldState.connection.state = import_types.ConnectionState.Closed;
927
+ oldState.storage.state = oldState.storage.state === import_types.StorageState.Synced ? import_types.StorageState.Offline : import_types.StorageState.Unavailable;
830
928
  oldState.webSocket = null;
831
929
  return oldState;
832
930
  });
@@ -891,9 +989,10 @@ var PluvRoom = class {
891
989
  this._detachWindowListeners();
892
990
  this._usersManager.removeMyself();
893
991
  this._usersManager.clearConnections();
894
- this._otherNotifier.clear();
992
+ this._usersNotifier.clear();
895
993
  this._stateNotifier.subjects.myself.next(null);
896
994
  this._stateNotifier.subjects.others.next([]);
995
+ this._usersNotifier.others.next({ others: [], event: { kind: "clear" } });
897
996
  (_c = this._state.webSocket) == null ? void 0 : _c.close();
898
997
  this._detachWsListeners();
899
998
  }
@@ -984,7 +1083,16 @@ var PluvRoom = class {
984
1083
  const deleted = this._usersManager.deleteConnection(connectionId);
985
1084
  const others = this._usersManager.getOthers();
986
1085
  this._stateNotifier.subjects.others.next(others);
987
- if (!(deleted == null ? void 0 : deleted.remaining) && !!clientId) this._otherNotifier.delete(clientId);
1086
+ if (!deleted) {
1087
+ console.warn("Could not identify exited connection");
1088
+ return;
1089
+ }
1090
+ const { data: user, remaining } = deleted;
1091
+ this._usersNotifier.others.next({
1092
+ others,
1093
+ event: { kind: "leave", user }
1094
+ });
1095
+ if (!remaining && !!clientId) this._usersNotifier.delete(clientId);
988
1096
  }
989
1097
  _handlePresenceUpdatedMessage(message) {
990
1098
  var _a;
@@ -1003,19 +1111,31 @@ var PluvRoom = class {
1003
1111
  return;
1004
1112
  }
1005
1113
  if (!!clientId) {
1006
- const other = this._usersManager.getOther(connectionId);
1007
- this._otherNotifier.subject(clientId).next(other);
1008
- } else {
1009
- const added = this._usersManager.addConnection({
1010
- connectionId,
1011
- presence: data.presence,
1012
- user: message.user
1013
- });
1014
- const other = this._usersManager.getOther(connectionId);
1015
- this._otherNotifier.subject(added.clientId).next(other);
1114
+ const other2 = this._usersManager.getOther(connectionId);
1115
+ const others2 = this._usersManager.getOthers();
1116
+ this._usersNotifier.other(clientId).next(other2);
1117
+ this._stateNotifier.subjects.others.next(others2);
1118
+ if (!!other2) {
1119
+ this._usersNotifier.others.next({
1120
+ others: others2,
1121
+ event: { kind: "update", user: other2 }
1122
+ });
1123
+ }
1124
+ return;
1016
1125
  }
1126
+ const added = this._usersManager.addConnection({
1127
+ connectionId,
1128
+ presence: data.presence,
1129
+ user: message.user
1130
+ });
1131
+ const other = this._usersManager.getOther(connectionId);
1017
1132
  const others = this._usersManager.getOthers();
1133
+ this._usersNotifier.other(added.clientId).next(other);
1018
1134
  this._stateNotifier.subjects.others.next(others);
1135
+ this._usersNotifier.others.next({
1136
+ others,
1137
+ event: { kind: "update", user: added.data }
1138
+ });
1019
1139
  }
1020
1140
  _handleReceiveOthers(message) {
1021
1141
  if (!message.connectionId) return;
@@ -1032,10 +1152,14 @@ var PluvRoom = class {
1032
1152
  if (result.isMyself) return;
1033
1153
  const clientId = result.clientId;
1034
1154
  const other = this._usersManager.getOther(connectionId);
1035
- this._otherNotifier.subject(clientId).next(other);
1155
+ this._usersNotifier.other(clientId).next(other);
1036
1156
  });
1037
1157
  const others = this._usersManager.getOthers();
1038
1158
  this._stateNotifier.subjects.others.next(others);
1159
+ this._usersNotifier.others.next({
1160
+ others,
1161
+ event: { kind: "sync", users: others }
1162
+ });
1039
1163
  }
1040
1164
  _handleRegisteredMessage(message) {
1041
1165
  return __async(this, null, function* () {
@@ -1047,7 +1171,6 @@ var PluvRoom = class {
1047
1171
  const data = message.data;
1048
1172
  const state = data.state;
1049
1173
  this._updateState((oldState) => {
1050
- oldState.connection.count += 1;
1051
1174
  oldState.connection.id = connectionId;
1052
1175
  oldState.authorization.user = user != null ? user : null;
1053
1176
  return oldState;
@@ -1099,6 +1222,10 @@ var PluvRoom = class {
1099
1222
  const encodedState = this._crdtManager.doc.getEncodedState();
1100
1223
  this._emitSharedTypes();
1101
1224
  this._observeCrdt();
1225
+ this._updateState((oldState) => {
1226
+ oldState.storage.state = import_types.StorageState.Synced;
1227
+ return oldState;
1228
+ });
1102
1229
  this._stateNotifier.subjects["storage-loaded"].next(true);
1103
1230
  this._sendMessage({
1104
1231
  type: "$updateStorage",
@@ -1137,6 +1264,11 @@ var PluvRoom = class {
1137
1264
  const quitters = this._usersManager.getOthers().filter((other) => !active.has(other.connectionId));
1138
1265
  quitters.forEach((quitter) => {
1139
1266
  this._usersManager.deleteConnection(quitter.connectionId);
1267
+ const remaining2 = this._usersManager.getOthers();
1268
+ this._usersNotifier.others.next({
1269
+ others: remaining2,
1270
+ event: { kind: "leave", user: quitter }
1271
+ });
1140
1272
  });
1141
1273
  const remaining = this._usersManager.getOthers();
1142
1274
  this._stateNotifier.subjects.others.next(remaining);
@@ -1159,8 +1291,12 @@ var PluvRoom = class {
1159
1291
  });
1160
1292
  const other = this._usersManager.getOther(connectionId);
1161
1293
  const others = this._usersManager.getOthers();
1162
- this._otherNotifier.subject(added.clientId).next(other);
1294
+ this._usersNotifier.other(added.clientId).next(other);
1163
1295
  this._stateNotifier.subjects.others.next(others);
1296
+ this._usersNotifier.others.next({
1297
+ others,
1298
+ event: { kind: "enter", user: added.data }
1299
+ });
1164
1300
  }
1165
1301
  _heartbeat() {
1166
1302
  this._clearTimeout(this._timeouts.pong);
@@ -1202,11 +1338,13 @@ var PluvRoom = class {
1202
1338
  this._listeners.onAuthorizationFail(authError);
1203
1339
  this._updateState((oldState) => {
1204
1340
  oldState.connection.state = import_types.ConnectionState.Unavailable;
1341
+ oldState.storage.state = import_types.StorageState.Unavailable;
1205
1342
  return oldState;
1206
1343
  });
1207
1344
  }
1208
1345
  _onClose(event) {
1209
1346
  return __async(this, null, function* () {
1347
+ this._listenerManager.subjects.close.next(event);
1210
1348
  this._logDebug("WebSocket closed");
1211
1349
  if (!!event.reason) this._logDebug(event.reason);
1212
1350
  const shouldRetry = [
@@ -1234,6 +1372,7 @@ var PluvRoom = class {
1234
1372
  */
1235
1373
  import_types.ConnectionState.Closed
1236
1374
  );
1375
+ oldState.storage.state = oldState.storage.state === import_types.StorageState.Synced ? import_types.StorageState.Offline : import_types.StorageState.Unavailable;
1237
1376
  oldState.webSocket = null;
1238
1377
  return oldState;
1239
1378
  });
@@ -1250,9 +1389,11 @@ var PluvRoom = class {
1250
1389
  * @description Handle websocket errors in a meaningful way, should they occur
1251
1390
  * @date August 19, 2022
1252
1391
  */
1253
- _onError() {
1392
+ _onError(event) {
1393
+ this._listenerManager.subjects.error.next(event);
1254
1394
  }
1255
1395
  _onMessage(event) {
1396
+ this._listenerManager.subjects.message.next(event);
1256
1397
  const message = this._parseMessage(event);
1257
1398
  if (!message) return;
1258
1399
  const shouldLog = typeof this._debug === "boolean" ? this._debug : this._debug.output.find((value) => value === message.type);
@@ -1300,7 +1441,8 @@ var PluvRoom = class {
1300
1441
  default:
1301
1442
  }
1302
1443
  }
1303
- _onOpen() {
1444
+ _onOpen(event) {
1445
+ this._listenerManager.subjects.open.next(event);
1304
1446
  if (this._state.connection.state !== import_types.ConnectionState.Connecting) return;
1305
1447
  this._logDebug("WebSocket connected");
1306
1448
  this._updateState((oldState) => {
@@ -1318,6 +1460,7 @@ var PluvRoom = class {
1318
1460
  if (this._state.connection.state === import_types.ConnectionState.Closed) return;
1319
1461
  this._updateState((oldState) => {
1320
1462
  oldState.connection.state = import_types.ConnectionState.Unavailable;
1463
+ oldState.storage.state = oldState.storage.state === import_types.StorageState.Synced ? import_types.StorageState.Offline : import_types.StorageState.Unavailable;
1321
1464
  return oldState;
1322
1465
  });
1323
1466
  });
@@ -1417,6 +1560,7 @@ var PluvRoom = class {
1417
1560
  const oldState = __spreadProps(__spreadValues({}, this._state), {
1418
1561
  authorization,
1419
1562
  connection: JSON.parse(JSON.stringify(this._state.connection)),
1563
+ storage: JSON.parse(JSON.stringify(this._state.storage)),
1420
1564
  webSocket: this._state.webSocket
1421
1565
  });
1422
1566
  const newState = updater(oldState);
@@ -1533,9 +1677,13 @@ var infer = (callback) => callback;
1533
1677
  var import_types2 = require("@pluv/types");
1534
1678
  var MockedRoom = class {
1535
1679
  constructor(room, options) {
1680
+ /**
1681
+ * @deprecated To be removed in v3. Use `getStorageLoaded` instead.
1682
+ */
1683
+ this.storageLoaded = true;
1536
1684
  this._crdtNotifier = new CrdtNotifier();
1537
1685
  this._eventNotifier = new EventNotifier();
1538
- this._otherNotifier = new OtherNotifier();
1686
+ this._usersNotifier = new UsersNotifier();
1539
1687
  this._state = {
1540
1688
  authorization: {
1541
1689
  token: null,
@@ -1543,10 +1691,12 @@ var MockedRoom = class {
1543
1691
  },
1544
1692
  connection: {
1545
1693
  attempts: 0,
1546
- count: 1,
1547
1694
  id: null,
1548
1695
  state: import_types2.ConnectionState.Untouched
1549
1696
  },
1697
+ storage: {
1698
+ state: import_types2.StorageState.Unavailable
1699
+ },
1550
1700
  webSocket: null
1551
1701
  };
1552
1702
  this._stateNotifier = new StateNotifier();
@@ -1622,20 +1772,66 @@ var MockedRoom = class {
1622
1772
  this.other = (connectionId, callback) => {
1623
1773
  const clientId = this._usersManager.getClientId(connectionId);
1624
1774
  if (!clientId) return () => void 0;
1625
- return this._otherNotifier.subscribe(clientId, callback);
1775
+ return this._usersNotifier.subscribeOther(clientId, callback);
1626
1776
  };
1627
1777
  this.redo = () => {
1628
1778
  this._crdtManager.doc.redo();
1629
1779
  };
1630
- this.storage = (key, fn) => {
1631
- return this._crdtNotifier.subscribe(key, fn);
1632
- };
1780
+ this.storage = new Proxy(
1781
+ (key, callback) => this._crdtNotifier.subscribe(key, callback),
1782
+ {
1783
+ get: (fn, prop) => {
1784
+ if (!!prop) {
1785
+ return (callback) => {
1786
+ return this._crdtNotifier.subcribeRoot(callback);
1787
+ };
1788
+ }
1789
+ return (callback) => {
1790
+ return fn(prop, callback);
1791
+ };
1792
+ }
1793
+ }
1794
+ );
1633
1795
  this.storageRoot = (fn) => {
1634
1796
  return this._crdtNotifier.subcribeRoot(fn);
1635
1797
  };
1636
- this.subscribe = (name, callback) => {
1637
- return this._stateNotifier.subscribe(name, callback);
1638
- };
1798
+ this.subscribe = new Proxy(
1799
+ (name, callback) => {
1800
+ return this._stateNotifier.subscribe(name, callback);
1801
+ },
1802
+ {
1803
+ get: (fn, prop) => {
1804
+ if (prop === "connection") {
1805
+ return (callback) => {
1806
+ return fn("connection", callback);
1807
+ };
1808
+ }
1809
+ if (prop === "myPresence") {
1810
+ return (callback) => {
1811
+ return fn("my-presence", callback);
1812
+ };
1813
+ }
1814
+ if (prop === "myself") {
1815
+ return (callback) => {
1816
+ return fn("myself", callback);
1817
+ };
1818
+ }
1819
+ if (prop === "others") {
1820
+ return (callback) => {
1821
+ return this._usersNotifier.subscribeOthers(callback);
1822
+ };
1823
+ }
1824
+ if (prop === "storageLoaded") {
1825
+ return (callback) => {
1826
+ return fn("storage-loaded", callback);
1827
+ };
1828
+ }
1829
+ if (prop === "event") return this.event;
1830
+ if (prop === "other") return this.other;
1831
+ if (prop === "storage") return this.storage;
1832
+ }
1833
+ }
1834
+ );
1639
1835
  this.transact = (fn, origin) => {
1640
1836
  const _origin = origin != null ? origin : this._state.connection.id;
1641
1837
  const crdtManager = this._crdtManager;
@@ -1675,8 +1871,8 @@ var MockedRoom = class {
1675
1871
  });
1676
1872
  this._observeCrdt();
1677
1873
  }
1678
- get storageLoaded() {
1679
- return true;
1874
+ addEventListener(kind, handler) {
1875
+ return () => void 0;
1680
1876
  }
1681
1877
  getDoc() {
1682
1878
  return this._crdtManager.doc;
@@ -1686,6 +1882,9 @@ var MockedRoom = class {
1686
1882
  if (typeof type === "undefined") return this._crdtManager.doc.toJson();
1687
1883
  return this._crdtManager.doc.toJson(type);
1688
1884
  }
1885
+ getStorageLoaded() {
1886
+ return true;
1887
+ }
1689
1888
  _observeCrdt() {
1690
1889
  var _a, _b;
1691
1890
  (_b = (_a = this._subscriptions).observeCrdt) == null ? void 0 : _b.call(_a);