@pluv/client 0.18.0 → 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.
@@ -3,7 +3,7 @@ import type { IOLike, Id, InferIOInput, InferIOOutput, JsonObject } from "@pluv/
3
3
  import type { EventNotifierSubscriptionCallback } from "./EventNotifier";
4
4
  import type { OtherNotifierSubscriptionCallback } from "./OtherNotifier";
5
5
  import type { StateNotifierSubjects, SubscriptionCallback } from "./StateNotifier";
6
- import type { UserInfo, WebSocketConnection } from "./types";
6
+ import type { UpdateMyPresenceAction, UserInfo, WebSocketConnection } from "./types";
7
7
 
8
8
  export abstract class AbstractRoom<
9
9
  TIO extends IOLike,
@@ -70,5 +70,5 @@ export abstract class AbstractRoom<
70
70
 
71
71
  public abstract undo(): void;
72
72
 
73
- public abstract updateMyPresence(presence: Partial<TPresence>): void;
73
+ public abstract updateMyPresence(presence: UpdateMyPresenceAction<TPresence>): void;
74
74
  }
package/src/MockedRoom.ts CHANGED
@@ -12,7 +12,13 @@ import type { StateNotifierSubjects, SubscriptionCallback } from "./StateNotifie
12
12
  import { StateNotifier } from "./StateNotifier";
13
13
  import type { UsersManagerConfig } from "./UsersManager";
14
14
  import { UsersManager } from "./UsersManager";
15
- import type { InternalSubscriptions, UserInfo, WebSocketConnection, WebSocketState } from "./types";
15
+ import type {
16
+ InternalSubscriptions,
17
+ UpdateMyPresenceAction,
18
+ UserInfo,
19
+ WebSocketConnection,
20
+ WebSocketState,
21
+ } from "./types";
16
22
  import { ConnectionState } from "./types";
17
23
 
18
24
  export type MockedRoomEvents<TIO extends IOLike> = Partial<{
@@ -111,10 +117,10 @@ export class MockedRoom<
111
117
  return this._eventNotifier.subscribe(event, callback);
112
118
  };
113
119
 
114
- public getConnection(): WebSocketConnection {
120
+ public getConnection = (): WebSocketConnection => {
115
121
  // Create a read-only clone of the connection state
116
122
  return Object.freeze(JSON.parse(JSON.stringify(this._state.connection)));
117
- }
123
+ };
118
124
 
119
125
  public getDoc(): AbstractCrdtDoc<TStorage> {
120
126
  return this._crdtManager.doc;
@@ -199,8 +205,10 @@ export class MockedRoom<
199
205
  this._crdtManager.doc.undo();
200
206
  };
201
207
 
202
- public updateMyPresence = (presence: Partial<TPresence>): void => {
203
- this._usersManager.updateMyPresence(presence);
208
+ public updateMyPresence = (presence: UpdateMyPresenceAction<TPresence>): void => {
209
+ const newPresence = typeof presence === "function" ? presence(this.getMyPresence()) : presence;
210
+
211
+ this._usersManager.updateMyPresence(newPresence);
204
212
 
205
213
  const myPresence = this._usersManager.myPresence;
206
214
  const myself = this._usersManager.myself ?? null;
@@ -3,16 +3,12 @@ import type { Subject } from "wonka";
3
3
  import { makeSubject, subscribe } from "wonka";
4
4
  import type { UserInfo } from "./types";
5
5
 
6
- export type OtherNotifierSubscriptionCallback<TIO extends IOLike> = (
7
- value: Id<UserInfo<TIO>> | null,
8
- ) => void;
6
+ export type OtherNotifierSubscriptionCallback<TIO extends IOLike> = (value: Id<UserInfo<TIO>> | null) => void;
9
7
 
10
8
  export class OtherNotifier<TIO extends IOLike> {
11
9
  public subjects = new Map<string, Subject<Id<UserInfo<TIO>> | null>>();
12
10
 
13
- public subject<TEvent extends string>(
14
- name: TEvent,
15
- ): Subject<Id<UserInfo<TIO>> | null> {
11
+ public subject<TEvent extends string>(name: TEvent): Subject<Id<UserInfo<TIO>> | null> {
16
12
  const subject = this.subjects.get(name);
17
13
 
18
14
  if (subject) return subject;
package/src/PluvRoom.ts CHANGED
@@ -26,7 +26,14 @@ import { StateNotifier } from "./StateNotifier";
26
26
  import { StorageStore } from "./StorageStore";
27
27
  import type { UsersManagerConfig } from "./UsersManager";
28
28
  import { UsersManager } from "./UsersManager";
29
- import type { AuthorizationState, InternalSubscriptions, UserInfo, WebSocketConnection, WebSocketState } from "./types";
29
+ import type {
30
+ AuthorizationState,
31
+ InternalSubscriptions,
32
+ UpdateMyPresenceAction,
33
+ UserInfo,
34
+ WebSocketConnection,
35
+ WebSocketState,
36
+ } from "./types";
30
37
  import { ConnectionState } from "./types";
31
38
  import { debounce } from "./utils";
32
39
 
@@ -347,14 +354,14 @@ export class PluvRoom<
347
354
  [event in keyof InferIOOutput<TIO>]: (callback: EventNotifierSubscriptionCallback<TIO, event>) => () => void;
348
355
  };
349
356
 
350
- public getConnection(): WebSocketConnection {
357
+ public getConnection = (): WebSocketConnection => {
351
358
  // Create a read-only clone of the connection state
352
359
  return Object.freeze(JSON.parse(JSON.stringify(this._state.connection)));
353
- }
360
+ };
354
361
 
355
- public getDoc(): AbstractCrdtDoc<TStorage> {
362
+ public getDoc = (): AbstractCrdtDoc<TStorage> => {
356
363
  return this._crdtManager.doc;
357
- }
364
+ };
358
365
 
359
366
  public getMyPresence = (): TPresence => {
360
367
  return this._usersManager.myPresence;
@@ -433,8 +440,10 @@ export class PluvRoom<
433
440
  this._crdtManager.doc.undo();
434
441
  };
435
442
 
436
- public updateMyPresence = (presence: Partial<TPresence>): void => {
437
- 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);
438
447
 
439
448
  const myPresence = this._usersManager.myPresence;
440
449
  const myself = this._usersManager.myself ?? null;
@@ -442,7 +451,7 @@ export class PluvRoom<
442
451
  this._stateNotifier.subjects["my-presence"].next(myPresence);
443
452
  !!myself && this._stateNotifier.subjects["myself"].next(myself);
444
453
 
445
- this.broadcast("$UPDATE_PRESENCE" as keyof InferIOInput<TIO>, { presence } as any);
454
+ this.broadcast("$UPDATE_PRESENCE" as keyof InferIOInput<TIO>, { presence: newPresence } as any);
446
455
  };
447
456
 
448
457
  private async _addToStorageStore(update: string): Promise<void> {
@@ -705,8 +714,6 @@ export class PluvRoom<
705
714
  Object.keys(data.others).forEach((connectionId) => {
706
715
  const { presence, user } = data.others[connectionId];
707
716
 
708
- if (!user) return;
709
-
710
717
  this._usersManager.setUser(connectionId, user);
711
718
 
712
719
  const other = this._usersManager.getOther(connectionId);
package/src/types.ts CHANGED
@@ -17,6 +17,16 @@ export interface InternalSubscriptions {
17
17
  observeCrdt: (() => void) | null;
18
18
  }
19
19
 
20
+ export type UpdateMyPresenceAction<TPresence extends JsonObject> =
21
+ | Partial<TPresence>
22
+ | ((oldPresence: TPresence | null) => Partial<TPresence>);
23
+
24
+ export interface UserInfo<TIO extends IOLike, TPresence extends JsonObject = {}> {
25
+ connectionId: string;
26
+ presence: TPresence;
27
+ user: Id<InferIOAuthorizeUser<InferIOAuthorize<TIO>>>;
28
+ }
29
+
20
30
  export interface WebSocketConnection {
21
31
  count: number;
22
32
  id: string | null;
@@ -28,9 +38,3 @@ export interface WebSocketState<TIO extends IOLike> {
28
38
  connection: WebSocketConnection;
29
39
  webSocket: WebSocket | null;
30
40
  }
31
-
32
- export interface UserInfo<TIO extends IOLike, TPresence extends JsonObject = {}> {
33
- connectionId: string;
34
- presence: TPresence;
35
- user: Id<InferIOAuthorizeUser<InferIOAuthorize<TIO>>>;
36
- }