@pluv/client 0.11.1 → 0.12.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/MockedRoom.ts CHANGED
@@ -31,14 +31,14 @@ import { UsersManager } from "./UsersManager";
31
31
 
32
32
  export type MockedRoomEvents<TIO extends IOLike> = Partial<{
33
33
  [P in keyof InferIOInput<TIO>]: (
34
- data: Id<InferIOInput<TIO>[P]>
34
+ data: Id<InferIOInput<TIO>[P]>,
35
35
  ) => Partial<InferIOOutput<TIO>>;
36
36
  }>;
37
37
 
38
38
  export type MockedRoomConfig<
39
39
  TIO extends IOLike,
40
40
  TPresence extends JsonObject = {},
41
- TStorage extends Record<string, AbstractType<any>> = {}
41
+ TStorage extends Record<string, AbstractType<any>> = {},
42
42
  > = { events?: MockedRoomEvents<TIO> } & Omit<
43
43
  CrdtManagerOptions<TStorage>,
44
44
  "encodedState"
@@ -48,7 +48,7 @@ export type MockedRoomConfig<
48
48
  export class MockedRoom<
49
49
  TIO extends IOLike,
50
50
  TPresence extends JsonObject = {},
51
- TStorage extends Record<string, AbstractType<any>> = {}
51
+ TStorage extends Record<string, AbstractType<any>> = {},
52
52
  > extends AbstractRoom<TIO, TPresence, TStorage> {
53
53
  private _crdtManager: CrdtManager<TStorage> | null = null;
54
54
  private _crdtNotifier = new CrdtNotifier<TStorage>();
@@ -75,7 +75,7 @@ export class MockedRoom<
75
75
 
76
76
  constructor(
77
77
  room: string,
78
- options: MockedRoomConfig<TIO, TPresence, TStorage>
78
+ options: MockedRoomConfig<TIO, TPresence, TStorage>,
79
79
  ) {
80
80
  const { events, initialPresence, initialStorage, presence } = options;
81
81
 
@@ -97,7 +97,7 @@ export class MockedRoom<
97
97
 
98
98
  public broadcast<TEvent extends keyof InferIOInput<TIO>>(
99
99
  event: TEvent,
100
- data: Id<InferIOInput<TIO>[TEvent]>
100
+ data: Id<InferIOInput<TIO>[TEvent]>,
101
101
  ): void {
102
102
  if (!this._events) return;
103
103
 
@@ -117,9 +117,17 @@ export class MockedRoom<
117
117
  });
118
118
  }
119
119
 
120
+ public canRedo = (): boolean => {
121
+ return !!this._crdtManager?.doc.canRedo();
122
+ };
123
+
124
+ public canUndo = (): boolean => {
125
+ return !!this._crdtManager?.doc.canUndo();
126
+ };
127
+
120
128
  public event = <TEvent extends keyof InferIOOutput<TIO>>(
121
129
  event: TEvent,
122
- callback: EventNotifierSubscriptionCallback<TIO, TEvent>
130
+ callback: EventNotifierSubscriptionCallback<TIO, TEvent>,
123
131
  ): (() => void) => {
124
132
  return this._eventNotifier.subscribe(event, callback);
125
133
  };
@@ -127,7 +135,7 @@ export class MockedRoom<
127
135
  public getConnection(): WebSocketConnection {
128
136
  // Create a read-only clone of the connection state
129
137
  return Object.freeze(
130
- JSON.parse(JSON.stringify(this._state.connection))
138
+ JSON.parse(JSON.stringify(this._state.connection)),
131
139
  );
132
140
  }
133
141
 
@@ -140,7 +148,7 @@ export class MockedRoom<
140
148
  };
141
149
 
142
150
  public getOther = (
143
- connectionId: string
151
+ connectionId: string,
144
152
  ): Id<UserInfo<TIO, TPresence>> | null => {
145
153
  return this._usersManager.getOther(connectionId);
146
154
  };
@@ -150,34 +158,72 @@ export class MockedRoom<
150
158
  };
151
159
 
152
160
  public getStorage = <TKey extends keyof TStorage>(
153
- key: TKey
161
+ key: TKey,
154
162
  ): TStorage[TKey] | null => {
155
163
  return this._crdtManager?.get(key) ?? null;
156
164
  };
157
165
 
158
166
  public other = (
159
167
  connectionId: string,
160
- callback: OtherNotifierSubscriptionCallback<TIO>
168
+ callback: OtherNotifierSubscriptionCallback<TIO>,
161
169
  ): (() => void) => {
162
170
  return this._otherNotifier.subscribe(connectionId, callback);
163
171
  };
164
172
 
173
+ public redo = (): void => {
174
+ this._crdtManager?.doc.redo();
175
+ };
176
+
165
177
  public storage = <TKey extends keyof TStorage>(
166
178
  key: TKey,
167
- fn: (value: InferYjsSharedTypeJson<TStorage[TKey]>) => void
179
+ fn: (value: InferYjsSharedTypeJson<TStorage[TKey]>) => void,
168
180
  ): (() => void) => {
169
181
  return this._crdtNotifier.subscribe(key, fn);
170
182
  };
171
183
 
184
+ public storageRoot = (
185
+ fn: (value: {
186
+ [P in keyof TStorage]: InferYjsSharedTypeJson<TStorage[P]>;
187
+ }) => void,
188
+ ): (() => void) => {
189
+ return this._crdtNotifier.subcribeRoot(fn);
190
+ };
191
+
172
192
  public subscribe = <
173
- TSubject extends keyof StateNotifierSubjects<TIO, TPresence>
193
+ TSubject extends keyof StateNotifierSubjects<TIO, TPresence>,
174
194
  >(
175
195
  name: TSubject,
176
- callback: SubscriptionCallback<TIO, TPresence, TSubject>
196
+ callback: SubscriptionCallback<TIO, TPresence, TSubject>,
177
197
  ): (() => void) => {
178
198
  return this._stateNotifier.subscribe(name, callback);
179
199
  };
180
200
 
201
+ public transact = (
202
+ fn: (storage: TStorage) => void,
203
+ origin?: string,
204
+ ): void => {
205
+ const _origin = origin ?? this._state.connection.id;
206
+ const crdtManager = this._crdtManager;
207
+
208
+ /**
209
+ * !HACK
210
+ * @description Don't transact anything if there is no origin, because
211
+ * that means the user isn't connected yet. This will mean events are
212
+ * lost unfortunately.
213
+ * @date September 23, 2023
214
+ */
215
+ if (typeof _origin !== "string") return;
216
+ if (!crdtManager) return;
217
+
218
+ crdtManager.doc.transact(() => {
219
+ fn(crdtManager.doc.storage);
220
+ }, _origin);
221
+ };
222
+
223
+ public undo = (): void => {
224
+ this._crdtManager?.doc.undo();
225
+ };
226
+
181
227
  public updateMyPresence = (presence: Partial<TPresence>): void => {
182
228
  this._usersManager.updateMyPresence(presence);
183
229
 
@@ -202,14 +248,25 @@ export class MockedRoom<
202
248
 
203
249
  const sharedTypes = this._crdtManager.doc.getSharedTypes();
204
250
 
205
- Object.entries(sharedTypes).forEach(([prop, sharedType]) => {
206
- if (!this._crdtManager) return;
251
+ const storageRoot = Object.entries(sharedTypes).reduce(
252
+ (acc, [prop, sharedType]) => {
253
+ if (!this._crdtManager) return acc;
254
+
255
+ const serialized = sharedType.toJSON();
256
+
257
+ this._crdtNotifier.subject(prop).next(serialized);
207
258
 
208
- const serialized = sharedType.toJSON();
259
+ return { ...acc, [prop]: serialized };
260
+ },
261
+ {} as {
262
+ [P in keyof TStorage]: InferYjsSharedTypeJson<
263
+ TStorage[P]
264
+ >;
265
+ },
266
+ );
209
267
 
210
- this._crdtNotifier.subject(prop).next(serialized);
211
- });
212
- }
268
+ this._crdtNotifier.rootSubject.next(storageRoot);
269
+ },
213
270
  );
214
271
 
215
272
  this._subscriptions.observeCrdt = unsubscribe;
@@ -4,14 +4,14 @@ import { makeSubject, subscribe } from "wonka";
4
4
  import { UserInfo } from "./types";
5
5
 
6
6
  export type OtherNotifierSubscriptionCallback<TIO extends IOLike> = (
7
- value: Id<UserInfo<TIO>> | null
7
+ value: Id<UserInfo<TIO>> | null,
8
8
  ) => void;
9
9
 
10
10
  export class OtherNotifier<TIO extends IOLike> {
11
11
  public subjects = new Map<string, Subject<Id<UserInfo<TIO>> | null>>();
12
12
 
13
13
  public subject<TEvent extends string>(
14
- name: TEvent
14
+ name: TEvent,
15
15
  ): Subject<Id<UserInfo<TIO>> | null> {
16
16
  const subject = this.subjects.get(name);
17
17
 
@@ -26,7 +26,7 @@ export class OtherNotifier<TIO extends IOLike> {
26
26
 
27
27
  public subscribe<TEvent extends string>(
28
28
  name: TEvent,
29
- callback: OtherNotifierSubscriptionCallback<TIO>
29
+ callback: OtherNotifierSubscriptionCallback<TIO>,
30
30
  ): () => void {
31
31
  const source = this.subject(name).source;
32
32
 
package/src/PluvClient.ts CHANGED
@@ -30,10 +30,10 @@ export class PluvClient<TIO extends IOLike = IOLike> {
30
30
 
31
31
  public createRoom = <
32
32
  TPresence extends JsonObject = {},
33
- TStorage extends Record<string, AbstractType<any>> = {}
33
+ TStorage extends Record<string, AbstractType<any>> = {},
34
34
  >(
35
35
  room: string,
36
- options: PluvRoomOptions<TIO, TPresence, TStorage> = {}
36
+ options: PluvRoomOptions<TIO, TPresence, TStorage> = {},
37
37
  ): PluvRoom<TIO, TPresence, TStorage> => {
38
38
  const oldRoom = this.getRoom<TPresence, TStorage>(room);
39
39
 
@@ -57,7 +57,7 @@ export class PluvClient<TIO extends IOLike = IOLike> {
57
57
  };
58
58
 
59
59
  public enter = async (
60
- room: string | PluvRoom<TIO, any, any>
60
+ room: string | PluvRoom<TIO, any, any>,
61
61
  ): Promise<PluvRoom<TIO, JsonObject, any>> => {
62
62
  const toEnter = typeof room === "string" ? this.getRoom(room) : room;
63
63
 
@@ -76,9 +76,9 @@ export class PluvClient<TIO extends IOLike = IOLike> {
76
76
 
77
77
  public getRoom = <
78
78
  TPresence extends JsonObject = {},
79
- TStorage extends Record<string, AbstractType<any>> = {}
79
+ TStorage extends Record<string, AbstractType<any>> = {},
80
80
  >(
81
- room: string
81
+ room: string,
82
82
  ): PluvRoom<TIO, TPresence, TStorage> | null => {
83
83
  const found = this._rooms.get(room) as
84
84
  | PluvRoom<TIO, TPresence, TStorage>
@@ -92,7 +92,7 @@ export class PluvClient<TIO extends IOLike = IOLike> {
92
92
  };
93
93
 
94
94
  public leave = async (
95
- room: string | PluvRoom<TIO, any, any>
95
+ room: string | PluvRoom<TIO, any, any>,
96
96
  ): Promise<void> => {
97
97
  const toLeave = typeof room === "string" ? this.getRoom(room) : room;
98
98
 
package/src/PluvRoom.ts CHANGED
@@ -1,4 +1,4 @@
1
- import { InferYjsSharedTypeJson } from "@pluv/crdt-yjs";
1
+ import { InferYjsSharedTypeJson, TrackOriginOptions } from "@pluv/crdt-yjs";
2
2
  import type {
3
3
  BaseIOEventRecord,
4
4
  EventMessage,
@@ -44,7 +44,8 @@ const ADD_TO_STORAGE_STATE_DEBOUNCE_MS = 1_000;
44
44
  const HEARTBEAT_INTERVAL_MS = 10_000;
45
45
  const PONG_TIMEOUT_MS = 2_000;
46
46
  const RECONNECT_TIMEOUT_MS = 30_000;
47
- const Y_ORIGIN_INITIALIZED = "$INITIALIZED";
47
+ const ORIGIN_INITIALIZED = "$INITIALIZED";
48
+ const ORIGIN_STORAGE_UPDATED = "$STORAGE_UPDATED";
48
49
 
49
50
  export const DEFAULT_PLUV_CLIENT_ADDON = <
50
51
  TIO extends IOLike = IOLike,
@@ -143,7 +144,9 @@ export type RoomConfig<
143
144
  TIO extends IOLike,
144
145
  TPresence extends JsonObject = {},
145
146
  TStorage extends Record<string, AbstractType<any>> = {},
146
- > = RoomEndpoints<TIO> & PluvRoomOptions<TIO, TPresence, TStorage>;
147
+ > = RoomEndpoints<TIO> &
148
+ PluvRoomOptions<TIO, TPresence, TStorage> &
149
+ TrackOriginOptions;
147
150
 
148
151
  export class PluvRoom<
149
152
  TIO extends IOLike,
@@ -152,6 +155,7 @@ export class PluvRoom<
152
155
  > extends AbstractRoom<TIO, TPresence, TStorage> {
153
156
  readonly _endpoints: RoomEndpoints<TIO>;
154
157
 
158
+ private _captureTimeout: number | null = null;
155
159
  private _crdtManager: CrdtManager<TStorage>;
156
160
  private _crdtNotifier = new CrdtNotifier<TStorage>();
157
161
  private _debug: boolean | PluvRoomDebug<TIO>;
@@ -182,6 +186,7 @@ export class PluvRoom<
182
186
  pong: null,
183
187
  reconnect: null,
184
188
  };
189
+ private _trackedOrigins: readonly string[] | null = null;
185
190
  private _windowListeners: WindowListeners | null = null;
186
191
  private _wsListeners: WebSocketListeners | null = null;
187
192
  private _usersManager: UsersManager<TIO, TPresence>;
@@ -190,11 +195,13 @@ export class PluvRoom<
190
195
  const {
191
196
  addons = [],
192
197
  authEndpoint,
198
+ captureTimeout,
193
199
  debug = false,
194
200
  initialPresence,
195
201
  initialStorage,
196
202
  onAuthorizationFail,
197
203
  presence,
204
+ trackedOrigins,
198
205
  wsEndpoint,
199
206
  } = options;
200
207
 
@@ -230,7 +237,14 @@ export class PluvRoom<
230
237
  presence,
231
238
  });
232
239
 
233
- this._crdtManager = new CrdtManager<TStorage>({ initialStorage });
240
+ this._crdtManager = new CrdtManager<TStorage>({
241
+ captureTimeout,
242
+ initialStorage,
243
+ trackedOrigins,
244
+ });
245
+
246
+ this._captureTimeout = captureTimeout ?? null;
247
+ this._trackedOrigins = trackedOrigins ?? null;
234
248
  }
235
249
 
236
250
  public get webSocket(): WebSocket | null {
@@ -249,6 +263,14 @@ export class PluvRoom<
249
263
  this._sendMessage({ data, type });
250
264
  }
251
265
 
266
+ public canRedo = (): boolean => {
267
+ return !!this._crdtManager.doc.canRedo();
268
+ };
269
+
270
+ public canUndo = (): boolean => {
271
+ return !!this._crdtManager.doc.canUndo();
272
+ };
273
+
252
274
  public async connect(): Promise<void> {
253
275
  if (!this._endpoints.wsEndpoint) {
254
276
  throw new Error("Must provide an wsEndpoint.");
@@ -272,8 +294,6 @@ export class PluvRoom<
272
294
  await this._storageStore.initialize();
273
295
  await this._applyStorageStore();
274
296
 
275
- console.log(this._getWsEndpoint(this.id));
276
-
277
297
  const url = new URL(this._getWsEndpoint(this.id));
278
298
 
279
299
  let authToken: string | null = null;
@@ -375,6 +395,10 @@ export class PluvRoom<
375
395
  return this._otherNotifier.subscribe(connectionId, callback);
376
396
  };
377
397
 
398
+ public redo = (): void => {
399
+ this._crdtManager.doc.redo();
400
+ };
401
+
378
402
  public storage = <TKey extends keyof TStorage>(
379
403
  key: TKey,
380
404
  fn: (value: InferYjsSharedTypeJson<TStorage[TKey]>) => void,
@@ -382,6 +406,14 @@ export class PluvRoom<
382
406
  return this._crdtNotifier.subscribe(key, fn);
383
407
  };
384
408
 
409
+ public storageRoot = (
410
+ fn: (value: {
411
+ [P in keyof TStorage]: InferYjsSharedTypeJson<TStorage[P]>;
412
+ }) => void,
413
+ ): (() => void) => {
414
+ return this._crdtNotifier.subcribeRoot(fn);
415
+ };
416
+
385
417
  public subscribe = <
386
418
  TSubject extends keyof StateNotifierSubjects<TIO, TPresence>,
387
419
  >(
@@ -391,6 +423,30 @@ export class PluvRoom<
391
423
  return this._stateNotifier.subscribe(name, callback);
392
424
  };
393
425
 
426
+ public transact = (
427
+ fn: (storage: TStorage) => void,
428
+ origin?: string,
429
+ ): void => {
430
+ const _origin = origin ?? this._state.connection.id;
431
+
432
+ /**
433
+ * !HACK
434
+ * @description Don't transact anything if there is no origin, because
435
+ * that means the user isn't connected yet. This will mean events are
436
+ * lost unfortunately.
437
+ * @date September 23, 2023
438
+ */
439
+ if (typeof _origin !== "string") return;
440
+
441
+ this._crdtManager.doc.transact(() => {
442
+ fn(this._crdtManager.doc.storage);
443
+ }, _origin);
444
+ };
445
+
446
+ public undo = (): void => {
447
+ this._crdtManager.doc.undo();
448
+ };
449
+
394
450
  public updateMyPresence = (presence: Partial<TPresence>): void => {
395
451
  this._usersManager.updateMyPresence(presence);
396
452
 
@@ -414,12 +470,15 @@ export class PluvRoom<
414
470
 
415
471
  private async _applyStorageStore(): Promise<void> {
416
472
  const updates = await this._storageStore.getUpdates();
473
+ const trackedOrigins = this._getTrackedOrigins();
417
474
 
418
475
  this._crdtManager.initialize({
476
+ captureTimeout: this._captureTimeout ?? undefined,
419
477
  onInitialized: () => {
420
478
  this._observeCrdt();
421
479
  },
422
- origin: Y_ORIGIN_INITIALIZED,
480
+ origin: ORIGIN_INITIALIZED,
481
+ trackedOrigins: trackedOrigins ?? undefined,
423
482
  update: updates,
424
483
  });
425
484
 
@@ -548,11 +607,20 @@ export class PluvRoom<
548
607
  private _emitSharedTypes(): void {
549
608
  const sharedTypes = this._crdtManager.doc.getSharedTypes();
550
609
 
551
- Object.entries(sharedTypes).forEach(([prop, sharedType]) => {
552
- const serialized = sharedType.toJSON();
610
+ const storageRoot = Object.entries(sharedTypes).reduce(
611
+ (acc, [prop, sharedType]) => {
612
+ const serialized = sharedType.toJSON();
553
613
 
554
- this._crdtNotifier.subject(prop).next(serialized);
555
- });
614
+ this._crdtNotifier.subject(prop).next(serialized);
615
+
616
+ return { ...acc, [prop]: serialized };
617
+ },
618
+ {} as {
619
+ [P in keyof TStorage]: InferYjsSharedTypeJson<TStorage[P]>;
620
+ },
621
+ );
622
+
623
+ this._crdtNotifier.rootSubject.next(storageRoot);
556
624
  }
557
625
 
558
626
  private _flattenStorageStore = debounce(
@@ -630,6 +698,14 @@ export class PluvRoom<
630
698
  }
631
699
  }
632
700
 
701
+ private _getTrackedOrigins(): readonly string[] | null {
702
+ const connectionId = this._state.connection.id;
703
+
704
+ return !connectionId
705
+ ? this._trackedOrigins
706
+ : [connectionId, ...(this._trackedOrigins ?? [])];
707
+ }
708
+
633
709
  private _getWsEndpoint(room: string): string {
634
710
  switch (typeof this._endpoints.wsEndpoint) {
635
711
  case "undefined":
@@ -772,11 +848,15 @@ export class PluvRoom<
772
848
  InferIOAuthorize<TIO>
773
849
  >["$STORAGE_RECEIVED"];
774
850
 
851
+ const trackedOrigins = this._getTrackedOrigins();
852
+
775
853
  this._crdtManager.initialize({
854
+ captureTimeout: this._captureTimeout ?? undefined,
776
855
  onInitialized: async () => {
777
856
  this._observeCrdt();
778
857
  },
779
- origin: Y_ORIGIN_INITIALIZED,
858
+ origin: ORIGIN_INITIALIZED,
859
+ trackedOrigins: trackedOrigins ?? undefined,
780
860
  update: data.state,
781
861
  });
782
862
 
@@ -790,7 +870,7 @@ export class PluvRoom<
790
870
 
791
871
  this._sendMessage({
792
872
  type: "$UPDATE_STORAGE",
793
- data: { origin: Y_ORIGIN_INITIALIZED, update },
873
+ data: { origin: ORIGIN_INITIALIZED, update },
794
874
  });
795
875
  }
796
876
 
@@ -803,21 +883,30 @@ export class PluvRoom<
803
883
 
804
884
  const data = message.data as BaseIOEventRecord<
805
885
  InferIOAuthorize<TIO>
806
- >["$STORAGE_UPDATED"];
886
+ >[typeof ORIGIN_STORAGE_UPDATED];
807
887
 
808
888
  if (!this._crdtManager) return;
809
889
 
810
- this._crdtManager.doc.applyUpdate(data.state, "$STORAGE_UPDATED");
890
+ this._crdtManager.doc.applyUpdate(data.state, ORIGIN_STORAGE_UPDATED);
811
891
 
812
892
  const sharedTypes = this._crdtManager.doc.getSharedTypes();
813
893
 
814
- Object.entries(sharedTypes).forEach(([prop, sharedType]) => {
815
- if (!this._crdtManager) return;
894
+ const storageRoot = Object.entries(sharedTypes).reduce(
895
+ (acc, [prop, sharedType]) => {
896
+ if (!this._crdtManager) return acc;
816
897
 
817
- const serialized = sharedType.toJSON();
898
+ const serialized = sharedType.toJSON();
818
899
 
819
- this._crdtNotifier.subject(prop).next(serialized);
820
- });
900
+ this._crdtNotifier.subject(prop).next(serialized);
901
+
902
+ return { ...acc, [prop]: serialized };
903
+ },
904
+ {} as {
905
+ [P in keyof TStorage]: InferYjsSharedTypeJson<TStorage[P]>;
906
+ },
907
+ );
908
+
909
+ this._crdtNotifier.rootSubject.next(storageRoot);
821
910
  }
822
911
 
823
912
  private _handleUserJoinedMessage(message: IOEventMessage<TIO>): void {
@@ -880,13 +969,13 @@ export class PluvRoom<
880
969
  this._addToStorageStore(update);
881
970
  this._emitSharedTypes();
882
971
 
883
- if (origin === Y_ORIGIN_INITIALIZED || origin === this) return;
972
+ if (origin === ORIGIN_INITIALIZED || origin === this) return;
884
973
 
885
974
  if (!this._state.webSocket) return;
886
975
  if (!this._state.connection.id) return;
887
976
  if (this._state.webSocket.readyState !== WebSocket.OPEN) return;
888
977
 
889
- if (origin === "$STORAGE_UPDATED") return;
978
+ if (origin === ORIGIN_STORAGE_UPDATED) return;
890
979
 
891
980
  this._sendMessage({
892
981
  type: "$UPDATE_STORAGE",
@@ -5,7 +5,7 @@ import type { UserInfo, WebSocketState } from "./types";
5
5
 
6
6
  export interface StateNotifierSubjects<
7
7
  TIO extends IOLike,
8
- TPresence extends JsonObject
8
+ TPresence extends JsonObject,
9
9
  > {
10
10
  connection: Subject<Id<WebSocketState<TIO>>>;
11
11
  "my-presence": Subject<TPresence | null>;
@@ -16,7 +16,7 @@ export interface StateNotifierSubjects<
16
16
  type InferSubjectValue<
17
17
  TIO extends IOLike,
18
18
  TPresence extends JsonObject,
19
- TSubject extends keyof StateNotifierSubjects<TIO, TPresence>
19
+ TSubject extends keyof StateNotifierSubjects<TIO, TPresence>,
20
20
  > = StateNotifierSubjects<TIO, TPresence>[TSubject] extends Subject<
21
21
  infer IValue
22
22
  >
@@ -26,12 +26,12 @@ type InferSubjectValue<
26
26
  export type SubscriptionCallback<
27
27
  TIO extends IOLike,
28
28
  TPresence extends JsonObject,
29
- TSubject extends keyof StateNotifierSubjects<TIO, TPresence>
29
+ TSubject extends keyof StateNotifierSubjects<TIO, TPresence>,
30
30
  > = (value: InferSubjectValue<TIO, TPresence, TSubject>) => void;
31
31
 
32
32
  export class StateNotifier<
33
33
  TIO extends IOLike,
34
- TPresence extends JsonObject = {}
34
+ TPresence extends JsonObject = {},
35
35
  > {
36
36
  public subjects: StateNotifierSubjects<TIO, TPresence> = {
37
37
  connection: makeSubject<Id<WebSocketState<TIO>>>(),
@@ -41,10 +41,10 @@ export class StateNotifier<
41
41
  };
42
42
 
43
43
  public subscribe<
44
- TSubject extends keyof StateNotifierSubjects<TIO, TPresence>
44
+ TSubject extends keyof StateNotifierSubjects<TIO, TPresence>,
45
45
  >(
46
46
  name: TSubject,
47
- callback: SubscriptionCallback<TIO, TPresence, TSubject>
47
+ callback: SubscriptionCallback<TIO, TPresence, TSubject>,
48
48
  ): () => void {
49
49
  const source = this.subjects[name]?.source as any;
50
50
 
@@ -17,7 +17,7 @@ export type UsersManagerConfig<TPresence extends JsonObject = {}> = {
17
17
 
18
18
  export class UsersManager<
19
19
  TIO extends IOLike,
20
- TPresence extends JsonObject = {}
20
+ TPresence extends JsonObject = {},
21
21
  > {
22
22
  private _initialPresence: TPresence;
23
23
  /**
@@ -62,7 +62,7 @@ export class UsersManager<
62
62
 
63
63
  public patchPresence(
64
64
  connectionId: string,
65
- patch: Partial<TPresence>
65
+ patch: Partial<TPresence>,
66
66
  ): void {
67
67
  if (this._myself?.connectionId === connectionId) {
68
68
  const presence = {
@@ -100,7 +100,7 @@ export class UsersManager<
100
100
 
101
101
  public setMyself(
102
102
  connectionId: string,
103
- user: Id<InferIOAuthorizeUser<InferIOAuthorize<TIO>>>
103
+ user: Id<InferIOAuthorizeUser<InferIOAuthorize<TIO>>>,
104
104
  ): void {
105
105
  this._myself = {
106
106
  connectionId,
@@ -129,7 +129,7 @@ export class UsersManager<
129
129
  public setUser(
130
130
  connectionId: string,
131
131
  user: Id<InferIOAuthorizeUser<InferIOAuthorize<TIO>>>,
132
- presence?: TPresence
132
+ presence?: TPresence,
133
133
  ): void {
134
134
  if (this._myself?.connectionId === connectionId) return;
135
135
 
@@ -3,7 +3,7 @@ import type { PluvClientOptions } from "./PluvClient";
3
3
  import { PluvClient } from "./PluvClient";
4
4
 
5
5
  export const createClient = <TIO extends IOLike = IOLike>(
6
- options: PluvClientOptions<TIO>
6
+ options: PluvClientOptions<TIO>,
7
7
  ): PluvClient<TIO> => {
8
8
  return new PluvClient<TIO>(options);
9
9
  };
package/src/index.ts CHANGED
@@ -1,4 +1,7 @@
1
- export type { InferYjsSharedTypeJson } from "@pluv/crdt-yjs";
1
+ export type {
2
+ InferYjsSharedTypeJson,
3
+ TrackOriginOptions,
4
+ } from "@pluv/crdt-yjs";
2
5
  export type {
3
6
  BaseUser,
4
7
  EventMessage,
package/src/types.ts CHANGED
@@ -37,7 +37,7 @@ export interface WebSocketState<TIO extends IOLike> {
37
37
 
38
38
  export interface UserInfo<
39
39
  TIO extends IOLike,
40
- TPresence extends JsonObject = {}
40
+ TPresence extends JsonObject = {},
41
41
  > {
42
42
  connectionId: string;
43
43
  presence: TPresence;