@pluv/client 0.17.3 → 0.19.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/src/PluvRoom.ts CHANGED
@@ -1,8 +1,4 @@
1
- import type {
2
- AbstractCrdtDoc,
3
- AbstractCrdtType,
4
- InferCrdtStorageJson,
5
- } from "@pluv/crdt";
1
+ import type { AbstractCrdtDoc, AbstractCrdtType, InferCrdtStorageJson } from "@pluv/crdt";
6
2
  import type {
7
3
  BaseIOEventRecord,
8
4
  EventMessage,
@@ -17,7 +13,7 @@ import type {
17
13
  JsonObject,
18
14
  } from "@pluv/types";
19
15
  import { AbstractRoom } from "./AbstractRoom";
20
- import { AbstractStorageStore } from "./AbstractStorageStore";
16
+ import type { AbstractStorageStore } from "./AbstractStorageStore";
21
17
  import type { CrdtManagerOptions } from "./CrdtManager";
22
18
  import { CrdtManager } from "./CrdtManager";
23
19
  import { CrdtNotifier } from "./CrdtNotifier";
@@ -25,10 +21,7 @@ import type { EventNotifierSubscriptionCallback } from "./EventNotifier";
25
21
  import { EventNotifier } from "./EventNotifier";
26
22
  import type { OtherNotifierSubscriptionCallback } from "./OtherNotifier";
27
23
  import { OtherNotifier } from "./OtherNotifier";
28
- import type {
29
- StateNotifierSubjects,
30
- SubscriptionCallback,
31
- } from "./StateNotifier";
24
+ import type { StateNotifierSubjects, SubscriptionCallback } from "./StateNotifier";
32
25
  import { StateNotifier } from "./StateNotifier";
33
26
  import { StorageStore } from "./StorageStore";
34
27
  import type { UsersManagerConfig } from "./UsersManager";
@@ -36,6 +29,7 @@ import { UsersManager } from "./UsersManager";
36
29
  import type {
37
30
  AuthorizationState,
38
31
  InternalSubscriptions,
32
+ UpdateMyPresenceAction,
39
33
  UserInfo,
40
34
  WebSocketConnection,
41
35
  WebSocketState,
@@ -89,10 +83,7 @@ interface TimeoutIds {
89
83
  reconnect: number | null;
90
84
  }
91
85
 
92
- export type AuthEndpoint =
93
- | string
94
- | ((room: string) => string | FetchOptions)
95
- | true;
86
+ export type AuthEndpoint = string | ((room: string) => string | FetchOptions) | true;
96
87
  export type WsEndpoint = string | ((room: string) => string);
97
88
 
98
89
  type FetchOptions = { url: string; options?: RequestInit };
@@ -111,9 +102,7 @@ export type PluvRoomAddon<
111
102
  TIO extends IOLike = IOLike,
112
103
  TPresence extends JsonObject = {},
113
104
  TStorage extends Record<string, AbstractCrdtType<any, any>> = {},
114
- > = (
115
- input: PluvRoomAddonInput<TIO, TPresence, TStorage>,
116
- ) => Partial<PluvRoomAddonResult>;
105
+ > = (input: PluvRoomAddonInput<TIO, TPresence, TStorage>) => Partial<PluvRoomAddonResult>;
117
106
 
118
107
  export interface PluvRoomAddonInput<
119
108
  TIO extends IOLike = IOLike,
@@ -220,10 +209,7 @@ export class PluvRoom<
220
209
  this._listeners = {
221
210
  onAuthorizationFail: (error) => {
222
211
  this._clearTimeout(this._timeouts.reconnect);
223
- this._timeouts.reconnect = setTimeout(
224
- this._reconnect.bind(this),
225
- RECONNECT_TIMEOUT_MS,
226
- );
212
+ this._timeouts.reconnect = setTimeout(this._reconnect.bind(this), RECONNECT_TIMEOUT_MS);
227
213
 
228
214
  onAuthorizationFail?.(error);
229
215
  },
@@ -247,17 +233,25 @@ export class PluvRoom<
247
233
  return this._state.webSocket;
248
234
  }
249
235
 
250
- public broadcast<TEvent extends keyof InferIOInput<TIO>>(
251
- event: TEvent,
252
- data: Id<InferIOInput<TIO>[TEvent]>,
253
- ): void {
254
- if (!this._state.webSocket) return;
255
- if (this._state.connection.state !== ConnectionState.Open) return;
236
+ public broadcast = new Proxy(
237
+ <TEvent extends keyof InferIOInput<TIO>>(event: TEvent, data: Id<InferIOInput<TIO>[TEvent]>): void => {
238
+ if (!this._state.webSocket) return;
239
+ if (this._state.connection.state !== ConnectionState.Open) return;
256
240
 
257
- const type = event.toString();
241
+ const type = event.toString();
258
242
 
259
- this._sendMessage({ data, type });
260
- }
243
+ this._sendMessage({ data, type });
244
+ },
245
+ {
246
+ get(fn, prop) {
247
+ return (data: Id<InferIOInput<TIO>[any]>): void => {
248
+ return fn(prop, data);
249
+ };
250
+ },
251
+ },
252
+ ) as (<TEvent extends keyof InferIOInput<TIO>>(event: TEvent, data: Id<InferIOInput<TIO>[TEvent]>) => void) & {
253
+ [event in keyof InferIOInput<TIO>]: (data: Id<InferIOInput<TIO>[event]>) => void;
254
+ };
261
255
 
262
256
  public canRedo = (): boolean => {
263
257
  return !!this._crdtManager.doc.canRedo();
@@ -272,10 +266,9 @@ export class PluvRoom<
272
266
  throw new Error("Must provide an wsEndpoint.");
273
267
  }
274
268
 
275
- const canConnect = [
276
- ConnectionState.Closed,
277
- ConnectionState.Untouched,
278
- ].some((state) => this._state.connection.state === state);
269
+ const canConnect = [ConnectionState.Closed, ConnectionState.Untouched].some(
270
+ (state) => this._state.connection.state === state,
271
+ );
279
272
 
280
273
  if (!canConnect) return;
281
274
 
@@ -298,8 +291,7 @@ export class PluvRoom<
298
291
  try {
299
292
  authToken = await this._getAuthorization(this.id);
300
293
 
301
- authToken &&
302
- url.searchParams.set("token", encodeURIComponent(authToken));
294
+ authToken && url.searchParams.set("token", encodeURIComponent(authToken));
303
295
 
304
296
  webSocket = new WebSocket(url.toString());
305
297
  } catch (err) {
@@ -328,10 +320,9 @@ export class PluvRoom<
328
320
 
329
321
  if (!this._state.webSocket) return;
330
322
 
331
- const canDisconnect = [
332
- ConnectionState.Connecting,
333
- ConnectionState.Open,
334
- ].some((state) => this._state.connection.state === state);
323
+ const canDisconnect = [ConnectionState.Connecting, ConnectionState.Open].some(
324
+ (state) => this._state.connection.state === state,
325
+ );
335
326
 
336
327
  if (!canDisconnect) return;
337
328
 
@@ -346,23 +337,31 @@ export class PluvRoom<
346
337
  this._stateNotifier.subjects["my-presence"].next(null);
347
338
  }
348
339
 
349
- public event = <TEvent extends keyof InferIOOutput<TIO>>(
340
+ public event = new Proxy(
341
+ <TEvent extends keyof InferIOOutput<TIO>>(
342
+ event: TEvent,
343
+ callback: EventNotifierSubscriptionCallback<TIO, TEvent>,
344
+ ): (() => void) => this._eventNotifier.subscribe(event, callback),
345
+ {
346
+ get(fn, prop) {
347
+ return (callback: EventNotifierSubscriptionCallback<TIO, any>): (() => void) => fn(prop, callback);
348
+ },
349
+ },
350
+ ) as (<TEvent extends keyof InferIOOutput<TIO>>(
350
351
  event: TEvent,
351
352
  callback: EventNotifierSubscriptionCallback<TIO, TEvent>,
352
- ): (() => void) => {
353
- return this._eventNotifier.subscribe(event, callback);
353
+ ) => () => void) & {
354
+ [event in keyof InferIOOutput<TIO>]: (callback: EventNotifierSubscriptionCallback<TIO, event>) => () => void;
354
355
  };
355
356
 
356
- public getConnection(): WebSocketConnection {
357
+ public getConnection = (): WebSocketConnection => {
357
358
  // Create a read-only clone of the connection state
358
- return Object.freeze(
359
- JSON.parse(JSON.stringify(this._state.connection)),
360
- );
361
- }
359
+ return Object.freeze(JSON.parse(JSON.stringify(this._state.connection)));
360
+ };
362
361
 
363
- public getDoc(): AbstractCrdtDoc<TStorage> {
362
+ public getDoc = (): AbstractCrdtDoc<TStorage> => {
364
363
  return this._crdtManager.doc;
365
- }
364
+ };
366
365
 
367
366
  public getMyPresence = (): TPresence => {
368
367
  return this._usersManager.myPresence;
@@ -372,9 +371,7 @@ export class PluvRoom<
372
371
  return this._usersManager.myself;
373
372
  };
374
373
 
375
- public getOther = (
376
- connectionId: string,
377
- ): Id<UserInfo<TIO, TPresence>> | null => {
374
+ public getOther = (connectionId: string): Id<UserInfo<TIO, TPresence>> | null => {
378
375
  return this._usersManager.getOther(connectionId);
379
376
  };
380
377
 
@@ -382,9 +379,7 @@ export class PluvRoom<
382
379
  return this._usersManager.getOthers();
383
380
  };
384
381
 
385
- public getStorage = <TKey extends keyof TStorage>(
386
- key: TKey,
387
- ): TStorage[TKey] | null => {
382
+ public getStorage = <TKey extends keyof TStorage>(key: TKey): TStorage[TKey] | null => {
388
383
  const sharedType = this._crdtManager.get(key);
389
384
 
390
385
  if (typeof sharedType === "undefined") return null;
@@ -392,10 +387,7 @@ export class PluvRoom<
392
387
  return sharedType;
393
388
  };
394
389
 
395
- public other = (
396
- connectionId: string,
397
- callback: OtherNotifierSubscriptionCallback<TIO>,
398
- ): (() => void) => {
390
+ public other = (connectionId: string, callback: OtherNotifierSubscriptionCallback<TIO>): (() => void) => {
399
391
  return this._otherNotifier.subscribe(connectionId, callback);
400
392
  };
401
393
 
@@ -418,19 +410,14 @@ export class PluvRoom<
418
410
  return this._crdtNotifier.subcribeRoot(fn);
419
411
  };
420
412
 
421
- public subscribe = <
422
- TSubject extends keyof StateNotifierSubjects<TIO, TPresence>,
423
- >(
413
+ public subscribe = <TSubject extends keyof StateNotifierSubjects<TIO, TPresence>>(
424
414
  name: TSubject,
425
415
  callback: SubscriptionCallback<TIO, TPresence, TSubject>,
426
416
  ): (() => void) => {
427
417
  return this._stateNotifier.subscribe(name, callback);
428
418
  };
429
419
 
430
- public transact = (
431
- fn: (storage: TStorage) => void,
432
- origin?: string,
433
- ): void => {
420
+ public transact = (fn: (storage: TStorage) => void, origin?: string): void => {
434
421
  const _origin = origin ?? this._state.connection.id;
435
422
 
436
423
  /**
@@ -453,8 +440,10 @@ export class PluvRoom<
453
440
  this._crdtManager.doc.undo();
454
441
  };
455
442
 
456
- public updateMyPresence = (presence: Partial<TPresence>): void => {
457
- this._usersManager.updateMyPresence(presence);
443
+ public updateMyPresence = (presence: UpdateMyPresenceAction<TPresence>): void => {
444
+ const newPresence = typeof presence === "function" ? presence(this.getMyPresence()) : presence;
445
+
446
+ this._usersManager.updateMyPresence(newPresence);
458
447
 
459
448
  const myPresence = this._usersManager.myPresence;
460
449
  const myself = this._usersManager.myself ?? null;
@@ -462,10 +451,7 @@ export class PluvRoom<
462
451
  this._stateNotifier.subjects["my-presence"].next(myPresence);
463
452
  !!myself && this._stateNotifier.subjects["myself"].next(myself);
464
453
 
465
- this.broadcast(
466
- "$UPDATE_PRESENCE" as keyof InferIOInput<TIO>,
467
- { presence } as any,
468
- );
454
+ this.broadcast("$UPDATE_PRESENCE" as keyof InferIOInput<TIO>, { presence: newPresence } as any);
469
455
  };
470
456
 
471
457
  private async _addToStorageStore(update: string): Promise<void> {
@@ -499,14 +485,8 @@ export class PluvRoom<
499
485
  onVisibilityChange: this._onVisibilityChange.bind(this),
500
486
  };
501
487
 
502
- window.addEventListener(
503
- "online",
504
- this._windowListeners.onNavigatorOnline,
505
- );
506
- document.addEventListener(
507
- "visibilitychange",
508
- this._windowListeners.onVisibilityChange,
509
- );
488
+ window.addEventListener("online", this._windowListeners.onNavigatorOnline);
489
+ document.addEventListener("visibilitychange", this._windowListeners.onVisibilityChange);
510
490
  }
511
491
 
512
492
  private _attachWsListeners(): void {
@@ -519,22 +499,10 @@ export class PluvRoom<
519
499
  onOpen: this._onOpen.bind(this),
520
500
  };
521
501
 
522
- this._state.webSocket.addEventListener(
523
- "close",
524
- this._wsListeners.onClose,
525
- );
526
- this._state.webSocket.addEventListener(
527
- "error",
528
- this._wsListeners.onError,
529
- );
530
- this._state.webSocket.addEventListener(
531
- "message",
532
- this._wsListeners.onMessage,
533
- );
534
- this._state.webSocket.addEventListener(
535
- "open",
536
- this._wsListeners.onOpen,
537
- );
502
+ this._state.webSocket.addEventListener("close", this._wsListeners.onClose);
503
+ this._state.webSocket.addEventListener("error", this._wsListeners.onError);
504
+ this._state.webSocket.addEventListener("message", this._wsListeners.onMessage);
505
+ this._state.webSocket.addEventListener("open", this._wsListeners.onOpen);
538
506
  }
539
507
 
540
508
  private _clearInterval(interval: number | null) {
@@ -574,14 +542,8 @@ export class PluvRoom<
574
542
  if (typeof window === "undefined") return;
575
543
  if (typeof document === "undefined") return;
576
544
 
577
- window.removeEventListener(
578
- "online",
579
- this._windowListeners.onNavigatorOnline,
580
- );
581
- document.removeEventListener(
582
- "visibilitychange",
583
- this._windowListeners.onVisibilityChange,
584
- );
545
+ window.removeEventListener("online", this._windowListeners.onNavigatorOnline);
546
+ document.removeEventListener("visibilitychange", this._windowListeners.onVisibilityChange);
585
547
 
586
548
  this._windowListeners = null;
587
549
  }
@@ -589,22 +551,10 @@ export class PluvRoom<
589
551
  private _detachWsListeners(): void {
590
552
  if (!this._state.webSocket || !this._wsListeners) return;
591
553
 
592
- this._state.webSocket.removeEventListener(
593
- "close",
594
- this._wsListeners.onClose,
595
- );
596
- this._state.webSocket.removeEventListener(
597
- "error",
598
- this._wsListeners.onError,
599
- );
600
- this._state.webSocket.removeEventListener(
601
- "message",
602
- this._wsListeners.onMessage,
603
- );
604
- this._state.webSocket.removeEventListener(
605
- "open",
606
- this._wsListeners.onOpen,
607
- );
554
+ this._state.webSocket.removeEventListener("close", this._wsListeners.onClose);
555
+ this._state.webSocket.removeEventListener("error", this._wsListeners.onError);
556
+ this._state.webSocket.removeEventListener("message", this._wsListeners.onMessage);
557
+ this._state.webSocket.removeEventListener("open", this._wsListeners.onOpen);
608
558
 
609
559
  this._wsListeners = null;
610
560
  }
@@ -676,9 +626,7 @@ export class PluvRoom<
676
626
 
677
627
  const result = this._endpoints.authEndpoint(room);
678
628
 
679
- return typeof result === "string"
680
- ? { url: result, options: {} }
681
- : result;
629
+ return typeof result === "string" ? { url: result, options: {} } : result;
682
630
  }
683
631
 
684
632
  private async _getAuthorization(room: string): Promise<string | null> {
@@ -697,9 +645,7 @@ export class PluvRoom<
697
645
  try {
698
646
  return await res.text().then((text) => text.trim());
699
647
  } catch (err) {
700
- throw new Error(
701
- err instanceof Error ? err.message : "Room is unauthorized",
702
- );
648
+ throw new Error(err instanceof Error ? err.message : "Room is unauthorized");
703
649
  }
704
650
  }
705
651
 
@@ -737,14 +683,9 @@ export class PluvRoom<
737
683
  // Should not reach here
738
684
  if (!this._state.webSocket) throw new Error("Could not find WebSocket");
739
685
 
740
- const data = message.data as BaseIOEventRecord<
741
- InferIOAuthorize<TIO>
742
- >["$PRESENCE_UPDATED"];
686
+ const data = message.data as BaseIOEventRecord<InferIOAuthorize<TIO>>["$PRESENCE_UPDATED"];
743
687
 
744
- this._usersManager.patchPresence(
745
- connectionId,
746
- data.presence as TPresence,
747
- );
688
+ this._usersManager.patchPresence(connectionId, data.presence as TPresence);
748
689
 
749
690
  const myPresence = this._usersManager.myPresence;
750
691
  const myself = this._usersManager.myself ?? null;
@@ -768,24 +709,16 @@ export class PluvRoom<
768
709
  // Should not reach here
769
710
  if (!this._state.webSocket) throw new Error("Could not find WebSocket");
770
711
 
771
- const data = message.data as BaseIOEventRecord<
772
- InferIOAuthorize<TIO>
773
- >["$OTHERS_RECEIVED"];
712
+ const data = message.data as BaseIOEventRecord<InferIOAuthorize<TIO>>["$OTHERS_RECEIVED"];
774
713
 
775
714
  Object.keys(data.others).forEach((connectionId) => {
776
715
  const { presence, user } = data.others[connectionId];
777
716
 
778
- if (!user) return;
779
-
780
717
  this._usersManager.setUser(connectionId, user);
781
718
 
782
719
  const other = this._usersManager.getOther(connectionId);
783
720
 
784
- !!presence &&
785
- this._usersManager.patchPresence(
786
- connectionId,
787
- presence as TPresence,
788
- );
721
+ !!presence && this._usersManager.patchPresence(connectionId, presence as TPresence);
789
722
 
790
723
  this._otherNotifier.subject(connectionId).next(other);
791
724
  });
@@ -810,10 +743,7 @@ export class PluvRoom<
810
743
  return oldState;
811
744
  });
812
745
 
813
- this._usersManager.setMyself(
814
- connectionId,
815
- user as Id<InferIOAuthorizeUser<InferIOAuthorize<TIO>>>,
816
- );
746
+ this._usersManager.setMyself(connectionId, user as Id<InferIOAuthorizeUser<InferIOAuthorize<TIO>>>);
817
747
 
818
748
  const presence = this._usersManager.myPresence;
819
749
  const myself = this._usersManager.myself ?? null;
@@ -821,10 +751,7 @@ export class PluvRoom<
821
751
  this._stateNotifier.subjects["my-presence"].next(presence);
822
752
  this._stateNotifier.subjects["myself"].next(myself);
823
753
 
824
- const update =
825
- this._state.connection.count > 1
826
- ? this._crdtManager.doc.getEncodedState() ?? null
827
- : null;
754
+ const update = this._state.connection.count > 1 ? this._crdtManager.doc.getEncodedState() ?? null : null;
828
755
 
829
756
  this._sendMessage({
830
757
  type: "$INITIALIZE_SESSION",
@@ -832,18 +759,14 @@ export class PluvRoom<
832
759
  });
833
760
  }
834
761
 
835
- private async _handleStorageReceivedMessage(
836
- message: IOEventMessage<TIO>,
837
- ): Promise<void> {
762
+ private async _handleStorageReceivedMessage(message: IOEventMessage<TIO>): Promise<void> {
838
763
  const { connectionId } = message;
839
764
 
840
765
  if (!connectionId) return;
841
766
  // Should not reach here
842
767
  if (!this._state.webSocket) throw new Error("Could not find WebSocket");
843
768
 
844
- const data = message.data as BaseIOEventRecord<
845
- InferIOAuthorize<TIO>
846
- >["$STORAGE_RECEIVED"];
769
+ const data = message.data as BaseIOEventRecord<InferIOAuthorize<TIO>>["$STORAGE_RECEIVED"];
847
770
 
848
771
  this._crdtManager.initialize({
849
772
  onInitialized: async (update) => {
@@ -878,9 +801,7 @@ export class PluvRoom<
878
801
  // Should not reach here
879
802
  if (!this._state.webSocket) throw new Error("Could not find WebSocket");
880
803
 
881
- const data = message.data as BaseIOEventRecord<
882
- InferIOAuthorize<TIO>
883
- >[typeof ORIGIN_STORAGE_UPDATED];
804
+ const data = message.data as BaseIOEventRecord<InferIOAuthorize<TIO>>[typeof ORIGIN_STORAGE_UPDATED];
884
805
 
885
806
  if (!this._crdtManager) return;
886
807
 
@@ -917,9 +838,7 @@ export class PluvRoom<
917
838
  if (!this._state.webSocket) throw new Error("Could not find WebSocket");
918
839
  if (!this._usersManager.myself) return;
919
840
 
920
- const data = message.data as BaseIOEventRecord<
921
- InferIOAuthorize<TIO>
922
- >["$USER_JOINED"];
841
+ const data = message.data as BaseIOEventRecord<InferIOAuthorize<TIO>>["$USER_JOINED"];
923
842
 
924
843
  const myself = this._usersManager.myself;
925
844
 
@@ -927,11 +846,7 @@ export class PluvRoom<
927
846
  this._sendMessage({ type: "$GET_OTHERS", data: {} });
928
847
  }
929
848
 
930
- this._usersManager.setUser(
931
- connectionId,
932
- data.user,
933
- data.presence as TPresence,
934
- );
849
+ this._usersManager.setUser(connectionId, data.user, data.presence as TPresence);
935
850
 
936
851
  const other = this._usersManager.getOther(connectionId);
937
852
  const others = this._usersManager.getOthers();
@@ -942,10 +857,7 @@ export class PluvRoom<
942
857
 
943
858
  private _heartbeat(): void {
944
859
  this._clearTimeout(this._timeouts.pong);
945
- this._timeouts.pong = setTimeout(
946
- this._reconnect.bind(this),
947
- PONG_TIMEOUT_MS,
948
- );
860
+ this._timeouts.pong = setTimeout(this._reconnect.bind(this), PONG_TIMEOUT_MS);
949
861
 
950
862
  this._sendMessage({ type: "$PING", data: {} });
951
863
  }
@@ -968,10 +880,7 @@ export class PluvRoom<
968
880
  this._addToStorageStore(event.update);
969
881
  this._emitSharedTypes();
970
882
 
971
- if (
972
- origin === ORIGIN_INITIALIZED ||
973
- origin === ORIGIN_STORAGE_UPDATED
974
- ) {
883
+ if (origin === ORIGIN_INITIALIZED || origin === ORIGIN_STORAGE_UPDATED) {
975
884
  return;
976
885
  }
977
886
 
@@ -989,8 +898,7 @@ export class PluvRoom<
989
898
  }
990
899
 
991
900
  private _onAuthorizationFail(error: unknown): void {
992
- const authError =
993
- error instanceof Error ? error : new Error("Authorization failed");
901
+ const authError = error instanceof Error ? error : new Error("Authorization failed");
994
902
 
995
903
  this._listeners.onAuthorizationFail(authError);
996
904
 
@@ -1040,17 +948,13 @@ export class PluvRoom<
1040
948
  if (!message) return;
1041
949
 
1042
950
  const shouldLog =
1043
- typeof this._debug === "boolean"
1044
- ? this._debug
1045
- : this._debug.output.find((value) => value === message.type);
951
+ typeof this._debug === "boolean" ? this._debug : this._debug.output.find((value) => value === message.type);
1046
952
 
1047
953
  if (shouldLog) {
1048
954
  this._logDebug("WebSocket event received: ", message.type, message);
1049
955
  }
1050
956
 
1051
- this._eventNotifier
1052
- .subject(message.type as keyof InferIOOutput<TIO>)
1053
- .next(message as any);
957
+ this._eventNotifier.subject(message.type as keyof InferIOOutput<TIO>).next(message as any);
1054
958
 
1055
959
  const { connectionId } = message;
1056
960
 
@@ -1105,10 +1009,7 @@ export class PluvRoom<
1105
1009
  });
1106
1010
 
1107
1011
  this._clearInterval(this._intervals.heartbeat);
1108
- this._intervals.heartbeat = setInterval(
1109
- this._heartbeat.bind(this),
1110
- HEARTBEAT_INTERVAL_MS,
1111
- );
1012
+ this._intervals.heartbeat = setInterval(this._heartbeat.bind(this), HEARTBEAT_INTERVAL_MS);
1112
1013
  }
1113
1014
 
1114
1015
  private async _onNavigatorOnline(): Promise<void> {
@@ -1137,9 +1038,7 @@ export class PluvRoom<
1137
1038
  }
1138
1039
  }
1139
1040
 
1140
- private _parseMessage(message: {
1141
- data: string | ArrayBuffer;
1142
- }): IOEventMessage<TIO> | null {
1041
+ private _parseMessage(message: { data: string | ArrayBuffer }): IOEventMessage<TIO> | null {
1143
1042
  /**
1144
1043
  * !HACK
1145
1044
  * @description We'll only handle stringified JSONs for now
@@ -1181,17 +1080,13 @@ export class PluvRoom<
1181
1080
  await this.connect();
1182
1081
  }
1183
1082
 
1184
- private _sendMessage<
1185
- TMessage extends EventMessage<string, any> = EventMessage<string, any>,
1186
- >(data: TMessage): void {
1083
+ private _sendMessage<TMessage extends EventMessage<string, any> = EventMessage<string, any>>(data: TMessage): void {
1187
1084
  const webSocket = this._state.webSocket;
1188
1085
 
1189
1086
  if (webSocket?.readyState !== WebSocket.OPEN) return;
1190
1087
 
1191
1088
  const shouldLog =
1192
- typeof this._debug === "boolean"
1193
- ? this._debug
1194
- : this._debug.input.find((value) => value === data.type);
1089
+ typeof this._debug === "boolean" ? this._debug : this._debug.input.find((value) => value === data.type);
1195
1090
 
1196
1091
  if (shouldLog) {
1197
1092
  this._logDebug("WebSocket event sent: ", data.type, data);
@@ -1200,15 +1095,11 @@ export class PluvRoom<
1200
1095
  webSocket.send(JSON.stringify(data));
1201
1096
  }
1202
1097
 
1203
- private _updateState(
1204
- updater: (oldState: WebSocketState<TIO>) => WebSocketState<TIO>,
1205
- ): WebSocketState<TIO> {
1098
+ private _updateState(updater: (oldState: WebSocketState<TIO>) => WebSocketState<TIO>): WebSocketState<TIO> {
1206
1099
  let authorization: AuthorizationState<TIO>;
1207
1100
 
1208
1101
  try {
1209
- authorization = JSON.parse(
1210
- JSON.stringify(this._state.authorization),
1211
- );
1102
+ authorization = JSON.parse(JSON.stringify(this._state.authorization));
1212
1103
  } catch {
1213
1104
  throw new Error("User is not JSON serializable");
1214
1105
  }
@@ -3,10 +3,7 @@ import type { Subject } from "wonka";
3
3
  import { makeSubject, subscribe } from "wonka";
4
4
  import type { UserInfo, WebSocketState } from "./types";
5
5
 
6
- export interface StateNotifierSubjects<
7
- TIO extends IOLike,
8
- TPresence extends JsonObject,
9
- > {
6
+ export interface StateNotifierSubjects<TIO extends IOLike, TPresence extends JsonObject> {
10
7
  connection: Subject<Id<WebSocketState<TIO>>>;
11
8
  "my-presence": Subject<TPresence | null>;
12
9
  myself: Subject<Readonly<Id<UserInfo<TIO>>> | null>;
@@ -18,12 +15,7 @@ type InferSubjectValue<
18
15
  TIO extends IOLike,
19
16
  TPresence extends JsonObject,
20
17
  TSubject extends keyof StateNotifierSubjects<TIO, TPresence>,
21
- > =
22
- StateNotifierSubjects<TIO, TPresence>[TSubject] extends Subject<
23
- infer IValue
24
- >
25
- ? Id<IValue>
26
- : never;
18
+ > = StateNotifierSubjects<TIO, TPresence>[TSubject] extends Subject<infer IValue> ? Id<IValue> : never;
27
19
 
28
20
  export type SubscriptionCallback<
29
21
  TIO extends IOLike,
@@ -31,10 +23,7 @@ export type SubscriptionCallback<
31
23
  TSubject extends keyof StateNotifierSubjects<TIO, TPresence>,
32
24
  > = (value: InferSubjectValue<TIO, TPresence, TSubject>) => void;
33
25
 
34
- export class StateNotifier<
35
- TIO extends IOLike,
36
- TPresence extends JsonObject = {},
37
- > {
26
+ export class StateNotifier<TIO extends IOLike, TPresence extends JsonObject = {}> {
38
27
  public subjects: StateNotifierSubjects<TIO, TPresence> = {
39
28
  connection: makeSubject<Id<WebSocketState<TIO>>>(),
40
29
  "my-presence": makeSubject<TPresence>(),
@@ -43,9 +32,7 @@ export class StateNotifier<
43
32
  "storage-loaded": makeSubject<true>(),
44
33
  };
45
34
 
46
- public subscribe<
47
- TSubject extends keyof StateNotifierSubjects<TIO, TPresence>,
48
- >(
35
+ public subscribe<TSubject extends keyof StateNotifierSubjects<TIO, TPresence>>(
49
36
  name: TSubject,
50
37
  callback: SubscriptionCallback<TIO, TPresence, TSubject>,
51
38
  ): () => void {