@pluv/client 2.0.1 → 2.1.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
@@ -228,35 +228,6 @@ var EventNotifier = class {
228
228
  }
229
229
  };
230
230
 
231
- // src/OtherNotifier.ts
232
- var import_wonka3 = require("wonka");
233
- var OtherNotifier = class {
234
- 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;
253
- }
254
- subscribe(clientId, callback) {
255
- const source = this.subject(clientId).source;
256
- return (0, import_wonka3.subscribe)(callback)(source).unsubscribe;
257
- }
258
- };
259
-
260
231
  // src/PluvRouter.ts
261
232
  var PluvRouter = class _PluvRouter {
262
233
  constructor(events) {
@@ -285,22 +256,22 @@ var PluvRouter = class _PluvRouter {
285
256
  };
286
257
 
287
258
  // src/StateNotifier.ts
288
- var import_wonka4 = require("wonka");
259
+ var import_wonka3 = require("wonka");
289
260
  var StateNotifier = class {
290
261
  constructor() {
291
262
  this.subjects = {
292
- connection: (0, import_wonka4.makeSubject)(),
293
- "my-presence": (0, import_wonka4.makeSubject)(),
294
- myself: (0, import_wonka4.makeSubject)(),
295
- others: (0, import_wonka4.makeSubject)(),
296
- "storage-loaded": (0, import_wonka4.makeSubject)()
263
+ connection: (0, import_wonka3.makeSubject)(),
264
+ "my-presence": (0, import_wonka3.makeSubject)(),
265
+ myself: (0, import_wonka3.makeSubject)(),
266
+ others: (0, import_wonka3.makeSubject)(),
267
+ "storage-loaded": (0, import_wonka3.makeSubject)()
297
268
  };
298
269
  }
299
270
  subscribe(name, callback) {
300
271
  var _a;
301
272
  const source = (_a = this.subjects[name]) == null ? void 0 : _a.source;
302
273
  if (!source) throw new Error(`Could not subscribe to source: ${name}`);
303
- return (0, import_wonka4.subscribe)(callback)(source).unsubscribe;
274
+ return (0, import_wonka3.subscribe)(callback)(source).unsubscribe;
304
275
  }
305
276
  };
306
277
 
@@ -550,6 +521,43 @@ var UsersManager = class {
550
521
  }
551
522
  };
552
523
 
524
+ // src/UsersNotifier.ts
525
+ var import_wonka4 = require("wonka");
526
+ var UsersNotifier = class {
527
+ constructor() {
528
+ this.others = (0, import_wonka4.makeSubject)();
529
+ this._otherSubjects = /* @__PURE__ */ new Map();
530
+ }
531
+ clear() {
532
+ this._otherSubjects.forEach((subject) => {
533
+ subject.next(null);
534
+ });
535
+ this._otherSubjects.clear();
536
+ }
537
+ delete(clientId) {
538
+ this.other(clientId).next(null);
539
+ this._otherSubjects.delete(clientId);
540
+ }
541
+ other(clientId) {
542
+ const subject = this._otherSubjects.get(clientId);
543
+ if (subject) return subject;
544
+ const newSubject = (0, import_wonka4.makeSubject)();
545
+ this._otherSubjects.set(clientId, newSubject);
546
+ return newSubject;
547
+ }
548
+ subscribeOther(clientId, callback) {
549
+ const source = this.other(clientId).source;
550
+ const subscription = (0, import_wonka4.subscribe)(callback)(source);
551
+ return subscription.unsubscribe;
552
+ }
553
+ subscribeOthers(callback) {
554
+ const subscription = (0, import_wonka4.subscribe)(
555
+ ({ others, event }) => callback(others, event)
556
+ )(this.others.source);
557
+ return subscription.unsubscribe;
558
+ }
559
+ };
560
+
553
561
  // src/PluvRoom.ts
554
562
  var ADD_TO_STORAGE_STATE_DEBOUNCE_MS = 1e3;
555
563
  var HEARTBEAT_INTERVAL_MS = 1e4;
@@ -569,7 +577,6 @@ var PluvRoom = class {
569
577
  this._intervals = {
570
578
  heartbeat: null
571
579
  };
572
- this._otherNotifier = new OtherNotifier();
573
580
  this._publicKey = null;
574
581
  this._stateNotifier = new StateNotifier();
575
582
  this._subscriptions = {
@@ -579,6 +586,7 @@ var PluvRoom = class {
579
586
  pong: null,
580
587
  reconnect: null
581
588
  };
589
+ this._usersNotifier = new UsersNotifier();
582
590
  this._lastMetadata = null;
583
591
  this._state = {
584
592
  authorization: {
@@ -633,6 +641,9 @@ var PluvRoom = class {
633
641
  this.canUndo = () => {
634
642
  return !!this._crdtManager.doc.canUndo();
635
643
  };
644
+ /**
645
+ * @deprecated To be removed in v3. Use PluvRoom.subscribe.event instead
646
+ */
636
647
  this.event = new Proxy(
637
648
  (event, callback) => this._eventNotifier.subscribe(event, callback),
638
649
  {
@@ -664,23 +675,77 @@ var PluvRoom = class {
664
675
  if (typeof sharedType === "undefined") return null;
665
676
  return sharedType;
666
677
  };
678
+ /**
679
+ * @deprecated To be removed in v3. Use PluvRoom.subscribe.other instead
680
+ */
667
681
  this.other = (connectionId, callback) => {
668
682
  const clientId = this._usersManager.getClientId(connectionId);
669
683
  if (!clientId) return () => void 0;
670
- return this._otherNotifier.subscribe(clientId, callback);
684
+ return this._usersNotifier.subscribeOther(clientId, callback);
671
685
  };
672
686
  this.redo = () => {
673
687
  this._crdtManager.doc.redo();
674
688
  };
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);
689
+ /**
690
+ * @deprecated To be removed in v3. To be removed in v3. Use PluvRoom.subscribe.storage instead
691
+ */
692
+ this.storage = new Proxy(
693
+ (key, callback) => this._crdtNotifier.subscribe(key, callback),
694
+ {
695
+ get: (fn, prop) => {
696
+ if (!!prop) {
697
+ return (callback) => {
698
+ return this._crdtNotifier.subcribeRoot(callback);
699
+ };
700
+ }
701
+ return (callback) => {
702
+ return fn(prop, callback);
703
+ };
704
+ }
705
+ }
706
+ );
707
+ /**
708
+ * @deprecated To be removed in v3. Use PluvRoom.subscribe.storage instead
709
+ * @description Subscribes to the root storage object (serialized)
710
+ */
711
+ this.storageRoot = (callback) => {
712
+ return this._crdtNotifier.subcribeRoot(callback);
683
713
  };
714
+ this.subscribe = new Proxy(
715
+ (name, callback) => this._stateNotifier.subscribe(name, callback),
716
+ {
717
+ get: (fn, prop) => {
718
+ if (prop === "connection") {
719
+ return (callback) => {
720
+ return fn("connection", callback);
721
+ };
722
+ }
723
+ if (prop === "myPresence") {
724
+ return (callback) => {
725
+ return fn("my-presence", callback);
726
+ };
727
+ }
728
+ if (prop === "myself") {
729
+ return (callback) => {
730
+ return fn("myself", callback);
731
+ };
732
+ }
733
+ if (prop === "others") {
734
+ return (callback) => {
735
+ return this._usersNotifier.subscribeOthers(callback);
736
+ };
737
+ }
738
+ if (prop === "storageLoaded") {
739
+ return (callback) => {
740
+ return fn("storage-loaded", callback);
741
+ };
742
+ }
743
+ if (prop === "event") return this.event;
744
+ if (prop === "other") return this.other;
745
+ if (prop === "storage") return this.storage;
746
+ }
747
+ }
748
+ );
684
749
  this.transact = (fn, origin) => {
685
750
  const _origin = origin != null ? origin : this._state.connection.id;
686
751
  if (typeof _origin !== "string") return;
@@ -891,9 +956,10 @@ var PluvRoom = class {
891
956
  this._detachWindowListeners();
892
957
  this._usersManager.removeMyself();
893
958
  this._usersManager.clearConnections();
894
- this._otherNotifier.clear();
959
+ this._usersNotifier.clear();
895
960
  this._stateNotifier.subjects.myself.next(null);
896
961
  this._stateNotifier.subjects.others.next([]);
962
+ this._usersNotifier.others.next({ others: [], event: { kind: "clear" } });
897
963
  (_c = this._state.webSocket) == null ? void 0 : _c.close();
898
964
  this._detachWsListeners();
899
965
  }
@@ -984,7 +1050,16 @@ var PluvRoom = class {
984
1050
  const deleted = this._usersManager.deleteConnection(connectionId);
985
1051
  const others = this._usersManager.getOthers();
986
1052
  this._stateNotifier.subjects.others.next(others);
987
- if (!(deleted == null ? void 0 : deleted.remaining) && !!clientId) this._otherNotifier.delete(clientId);
1053
+ if (!deleted) {
1054
+ console.warn("Could not identify exited connection");
1055
+ return;
1056
+ }
1057
+ const { data: user, remaining } = deleted;
1058
+ this._usersNotifier.others.next({
1059
+ others,
1060
+ event: { kind: "leave", user }
1061
+ });
1062
+ if (!remaining && !!clientId) this._usersNotifier.delete(clientId);
988
1063
  }
989
1064
  _handlePresenceUpdatedMessage(message) {
990
1065
  var _a;
@@ -1003,19 +1078,31 @@ var PluvRoom = class {
1003
1078
  return;
1004
1079
  }
1005
1080
  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);
1081
+ const other2 = this._usersManager.getOther(connectionId);
1082
+ const others2 = this._usersManager.getOthers();
1083
+ this._usersNotifier.other(clientId).next(other2);
1084
+ this._stateNotifier.subjects.others.next(others2);
1085
+ if (!!other2) {
1086
+ this._usersNotifier.others.next({
1087
+ others: others2,
1088
+ event: { kind: "update", user: other2 }
1089
+ });
1090
+ }
1091
+ return;
1016
1092
  }
1093
+ const added = this._usersManager.addConnection({
1094
+ connectionId,
1095
+ presence: data.presence,
1096
+ user: message.user
1097
+ });
1098
+ const other = this._usersManager.getOther(connectionId);
1017
1099
  const others = this._usersManager.getOthers();
1100
+ this._usersNotifier.other(added.clientId).next(other);
1018
1101
  this._stateNotifier.subjects.others.next(others);
1102
+ this._usersNotifier.others.next({
1103
+ others,
1104
+ event: { kind: "update", user: added.data }
1105
+ });
1019
1106
  }
1020
1107
  _handleReceiveOthers(message) {
1021
1108
  if (!message.connectionId) return;
@@ -1032,10 +1119,14 @@ var PluvRoom = class {
1032
1119
  if (result.isMyself) return;
1033
1120
  const clientId = result.clientId;
1034
1121
  const other = this._usersManager.getOther(connectionId);
1035
- this._otherNotifier.subject(clientId).next(other);
1122
+ this._usersNotifier.other(clientId).next(other);
1036
1123
  });
1037
1124
  const others = this._usersManager.getOthers();
1038
1125
  this._stateNotifier.subjects.others.next(others);
1126
+ this._usersNotifier.others.next({
1127
+ others,
1128
+ event: { kind: "sync", users: others }
1129
+ });
1039
1130
  }
1040
1131
  _handleRegisteredMessage(message) {
1041
1132
  return __async(this, null, function* () {
@@ -1137,6 +1228,11 @@ var PluvRoom = class {
1137
1228
  const quitters = this._usersManager.getOthers().filter((other) => !active.has(other.connectionId));
1138
1229
  quitters.forEach((quitter) => {
1139
1230
  this._usersManager.deleteConnection(quitter.connectionId);
1231
+ const remaining2 = this._usersManager.getOthers();
1232
+ this._usersNotifier.others.next({
1233
+ others: remaining2,
1234
+ event: { kind: "leave", user: quitter }
1235
+ });
1140
1236
  });
1141
1237
  const remaining = this._usersManager.getOthers();
1142
1238
  this._stateNotifier.subjects.others.next(remaining);
@@ -1159,8 +1255,12 @@ var PluvRoom = class {
1159
1255
  });
1160
1256
  const other = this._usersManager.getOther(connectionId);
1161
1257
  const others = this._usersManager.getOthers();
1162
- this._otherNotifier.subject(added.clientId).next(other);
1258
+ this._usersNotifier.other(added.clientId).next(other);
1163
1259
  this._stateNotifier.subjects.others.next(others);
1260
+ this._usersNotifier.others.next({
1261
+ others,
1262
+ event: { kind: "enter", user: added.data }
1263
+ });
1164
1264
  }
1165
1265
  _heartbeat() {
1166
1266
  this._clearTimeout(this._timeouts.pong);
@@ -1535,7 +1635,7 @@ var MockedRoom = class {
1535
1635
  constructor(room, options) {
1536
1636
  this._crdtNotifier = new CrdtNotifier();
1537
1637
  this._eventNotifier = new EventNotifier();
1538
- this._otherNotifier = new OtherNotifier();
1638
+ this._usersNotifier = new UsersNotifier();
1539
1639
  this._state = {
1540
1640
  authorization: {
1541
1641
  token: null,
@@ -1622,20 +1722,66 @@ var MockedRoom = class {
1622
1722
  this.other = (connectionId, callback) => {
1623
1723
  const clientId = this._usersManager.getClientId(connectionId);
1624
1724
  if (!clientId) return () => void 0;
1625
- return this._otherNotifier.subscribe(clientId, callback);
1725
+ return this._usersNotifier.subscribeOther(clientId, callback);
1626
1726
  };
1627
1727
  this.redo = () => {
1628
1728
  this._crdtManager.doc.redo();
1629
1729
  };
1630
- this.storage = (key, fn) => {
1631
- return this._crdtNotifier.subscribe(key, fn);
1632
- };
1730
+ this.storage = new Proxy(
1731
+ (key, callback) => this._crdtNotifier.subscribe(key, callback),
1732
+ {
1733
+ get: (fn, prop) => {
1734
+ if (!!prop) {
1735
+ return (callback) => {
1736
+ return this._crdtNotifier.subcribeRoot(callback);
1737
+ };
1738
+ }
1739
+ return (callback) => {
1740
+ return fn(prop, callback);
1741
+ };
1742
+ }
1743
+ }
1744
+ );
1633
1745
  this.storageRoot = (fn) => {
1634
1746
  return this._crdtNotifier.subcribeRoot(fn);
1635
1747
  };
1636
- this.subscribe = (name, callback) => {
1637
- return this._stateNotifier.subscribe(name, callback);
1638
- };
1748
+ this.subscribe = new Proxy(
1749
+ (name, callback) => {
1750
+ return this._stateNotifier.subscribe(name, callback);
1751
+ },
1752
+ {
1753
+ get: (fn, prop) => {
1754
+ if (prop === "connection") {
1755
+ return (callback) => {
1756
+ return fn("connection", callback);
1757
+ };
1758
+ }
1759
+ if (prop === "myPresence") {
1760
+ return (callback) => {
1761
+ return fn("my-presence", callback);
1762
+ };
1763
+ }
1764
+ if (prop === "myself") {
1765
+ return (callback) => {
1766
+ return fn("myself", callback);
1767
+ };
1768
+ }
1769
+ if (prop === "others") {
1770
+ return (callback) => {
1771
+ return this._usersNotifier.subscribeOthers(callback);
1772
+ };
1773
+ }
1774
+ if (prop === "storageLoaded") {
1775
+ return (callback) => {
1776
+ return fn("storage-loaded", callback);
1777
+ };
1778
+ }
1779
+ if (prop === "event") return this.event;
1780
+ if (prop === "other") return this.other;
1781
+ if (prop === "storage") return this.storage;
1782
+ }
1783
+ }
1784
+ );
1639
1785
  this.transact = (fn, origin) => {
1640
1786
  const _origin = origin != null ? origin : this._state.connection.id;
1641
1787
  const crdtManager = this._crdtManager;