@pluv/client 0.15.0 → 0.16.1

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,18 +1,21 @@
1
- import { InferYjsSharedTypeJson, TrackOriginOptions } from "@pluv/crdt-yjs";
1
+ import type {
2
+ AbstractCrdtDoc,
3
+ AbstractCrdtType,
4
+ InferCrdtStorageJson,
5
+ } from "@pluv/crdt";
2
6
  import type {
3
7
  BaseIOEventRecord,
4
8
  EventMessage,
9
+ IOEventMessage,
10
+ IOLike,
5
11
  Id,
6
12
  InferIOAuthorize,
7
13
  InferIOAuthorizeRequired,
8
14
  InferIOAuthorizeUser,
9
15
  InferIOInput,
10
16
  InferIOOutput,
11
- IOEventMessage,
12
- IOLike,
13
17
  JsonObject,
14
18
  } from "@pluv/types";
15
- import type { AbstractType, Doc } from "yjs";
16
19
  import { AbstractRoom } from "./AbstractRoom";
17
20
  import { AbstractStorageStore } from "./AbstractStorageStore";
18
21
  import type { CrdtManagerOptions } from "./CrdtManager";
@@ -28,6 +31,8 @@ import type {
28
31
  } from "./StateNotifier";
29
32
  import { StateNotifier } from "./StateNotifier";
30
33
  import { StorageStore } from "./StorageStore";
34
+ import type { UsersManagerConfig } from "./UsersManager";
35
+ import { UsersManager } from "./UsersManager";
31
36
  import type {
32
37
  AuthorizationState,
33
38
  InternalSubscriptions,
@@ -36,8 +41,6 @@ import type {
36
41
  WebSocketState,
37
42
  } from "./types";
38
43
  import { ConnectionState } from "./types";
39
- import type { UsersManagerConfig } from "./UsersManager";
40
- import { UsersManager } from "./UsersManager";
41
44
  import { debounce } from "./utils";
42
45
 
43
46
  const ADD_TO_STORAGE_STATE_DEBOUNCE_MS = 1_000;
@@ -50,7 +53,7 @@ const ORIGIN_STORAGE_UPDATED = "$STORAGE_UPDATED";
50
53
  export const DEFAULT_PLUV_CLIENT_ADDON = <
51
54
  TIO extends IOLike = IOLike,
52
55
  TPresence extends JsonObject = {},
53
- TStorage extends Record<string, AbstractType<any>> = {},
56
+ TStorage extends Record<string, AbstractCrdtType<any, any>> = {},
54
57
  >(
55
58
  input: PluvRoomAddonInput<TIO, TPresence, TStorage>,
56
59
  ): PluvRoomAddonResult => ({
@@ -107,7 +110,7 @@ interface InternalListeners {
107
110
  export type PluvRoomAddon<
108
111
  TIO extends IOLike = IOLike,
109
112
  TPresence extends JsonObject = {},
110
- TStorage extends Record<string, AbstractType<any>> = {},
113
+ TStorage extends Record<string, AbstractCrdtType<any, any>> = {},
111
114
  > = (
112
115
  input: PluvRoomAddonInput<TIO, TPresence, TStorage>,
113
116
  ) => Partial<PluvRoomAddonResult>;
@@ -115,7 +118,7 @@ export type PluvRoomAddon<
115
118
  export interface PluvRoomAddonInput<
116
119
  TIO extends IOLike = IOLike,
117
120
  TPresence extends JsonObject = {},
118
- TStorage extends Record<string, AbstractType<any>> = {},
121
+ TStorage extends Record<string, AbstractCrdtType<any, any>> = {},
119
122
  > {
120
123
  room: PluvRoom<TIO, TPresence, TStorage>;
121
124
  }
@@ -132,7 +135,7 @@ export type PluvRoomDebug<TIO extends IOLike> = Id<{
132
135
  export type PluvRoomOptions<
133
136
  TIO extends IOLike,
134
137
  TPresence extends JsonObject = {},
135
- TStorage extends Record<string, AbstractType<any>> = {},
138
+ TStorage extends Record<string, AbstractCrdtType<any, any>> = {},
136
139
  > = {
137
140
  addons?: readonly PluvRoomAddon<TIO, TPresence, TStorage>[];
138
141
  debug?: boolean | PluvRoomDebug<TIO>;
@@ -143,19 +146,16 @@ export type PluvRoomOptions<
143
146
  export type RoomConfig<
144
147
  TIO extends IOLike,
145
148
  TPresence extends JsonObject = {},
146
- TStorage extends Record<string, AbstractType<any>> = {},
147
- > = RoomEndpoints<TIO> &
148
- PluvRoomOptions<TIO, TPresence, TStorage> &
149
- TrackOriginOptions;
149
+ TStorage extends Record<string, AbstractCrdtType<any, any>> = {},
150
+ > = RoomEndpoints<TIO> & PluvRoomOptions<TIO, TPresence, TStorage>;
150
151
 
151
152
  export class PluvRoom<
152
153
  TIO extends IOLike,
153
154
  TPresence extends JsonObject = {},
154
- TStorage extends Record<string, AbstractType<any>> = {},
155
+ TStorage extends Record<string, AbstractCrdtType<any, any>> = {},
155
156
  > extends AbstractRoom<TIO, TPresence, TStorage> {
156
157
  readonly _endpoints: RoomEndpoints<TIO>;
157
158
 
158
- private _captureTimeout: number | null = null;
159
159
  private _crdtManager: CrdtManager<TStorage>;
160
160
  private _crdtNotifier = new CrdtNotifier<TStorage>();
161
161
  private _debug: boolean | PluvRoomDebug<TIO>;
@@ -186,7 +186,6 @@ export class PluvRoom<
186
186
  pong: null,
187
187
  reconnect: null,
188
188
  };
189
- private _trackedOrigins: readonly string[] | null = null;
190
189
  private _windowListeners: WindowListeners | null = null;
191
190
  private _wsListeners: WebSocketListeners | null = null;
192
191
  private _usersManager: UsersManager<TIO, TPresence>;
@@ -195,13 +194,11 @@ export class PluvRoom<
195
194
  const {
196
195
  addons = [],
197
196
  authEndpoint,
198
- captureTimeout,
199
197
  debug = false,
200
198
  initialPresence,
201
199
  initialStorage,
202
200
  onAuthorizationFail,
203
201
  presence,
204
- trackedOrigins,
205
202
  wsEndpoint,
206
203
  } = options;
207
204
 
@@ -238,13 +235,12 @@ export class PluvRoom<
238
235
  });
239
236
 
240
237
  this._crdtManager = new CrdtManager<TStorage>({
241
- captureTimeout,
242
238
  initialStorage,
243
- trackedOrigins,
244
239
  });
240
+ }
245
241
 
246
- this._captureTimeout = captureTimeout ?? null;
247
- this._trackedOrigins = trackedOrigins ?? null;
242
+ public get storageLoaded(): boolean {
243
+ return this._crdtManager.initialized;
248
244
  }
249
245
 
250
246
  public get webSocket(): WebSocket | null {
@@ -364,8 +360,8 @@ export class PluvRoom<
364
360
  );
365
361
  }
366
362
 
367
- public getDoc(): Doc {
368
- return this._crdtManager.doc.value;
363
+ public getDoc(): AbstractCrdtDoc<TStorage> {
364
+ return this._crdtManager.doc;
369
365
  }
370
366
 
371
367
  public getMyPresence = (): TPresence => {
@@ -388,12 +384,10 @@ export class PluvRoom<
388
384
 
389
385
  public getStorage = <TKey extends keyof TStorage>(
390
386
  key: TKey,
391
- ): TStorage[TKey] => {
387
+ ): TStorage[TKey] | null => {
392
388
  const sharedType = this._crdtManager.get(key);
393
389
 
394
- if (typeof sharedType === "undefined") {
395
- throw new Error(`Could not find storege: ${key.toString()}`);
396
- }
390
+ if (typeof sharedType === "undefined") return null;
397
391
 
398
392
  return sharedType;
399
393
  };
@@ -411,14 +405,14 @@ export class PluvRoom<
411
405
 
412
406
  public storage = <TKey extends keyof TStorage>(
413
407
  key: TKey,
414
- fn: (value: InferYjsSharedTypeJson<TStorage[TKey]>) => void,
408
+ fn: (value: InferCrdtStorageJson<TStorage[TKey]>) => void,
415
409
  ): (() => void) => {
416
410
  return this._crdtNotifier.subscribe(key, fn);
417
411
  };
418
412
 
419
413
  public storageRoot = (
420
414
  fn: (value: {
421
- [P in keyof TStorage]: InferYjsSharedTypeJson<TStorage[P]>;
415
+ [P in keyof TStorage]: InferCrdtStorageJson<TStorage[P]>;
422
416
  }) => void,
423
417
  ): (() => void) => {
424
418
  return this._crdtNotifier.subcribeRoot(fn);
@@ -449,7 +443,9 @@ export class PluvRoom<
449
443
  if (typeof _origin !== "string") return;
450
444
 
451
445
  this._crdtManager.doc.transact(() => {
452
- fn(this._crdtManager.doc.storage);
446
+ const storage = this._crdtManager.doc.get();
447
+
448
+ fn(storage);
453
449
  }, _origin);
454
450
  };
455
451
 
@@ -480,15 +476,14 @@ export class PluvRoom<
480
476
 
481
477
  private async _applyStorageStore(): Promise<void> {
482
478
  const updates = await this._storageStore.getUpdates();
483
- const trackedOrigins = this._getTrackedOrigins();
484
479
 
485
480
  this._crdtManager.initialize({
486
- captureTimeout: this._captureTimeout ?? undefined,
487
481
  onInitialized: () => {
482
+ this._stateNotifier.subjects["storage-loaded"].next(true);
483
+
488
484
  this._observeCrdt();
489
485
  },
490
486
  origin: ORIGIN_INITIALIZED,
491
- trackedOrigins: trackedOrigins ?? undefined,
492
487
  update: updates,
493
488
  });
494
489
 
@@ -615,18 +610,18 @@ export class PluvRoom<
615
610
  }
616
611
 
617
612
  private _emitSharedTypes(): void {
618
- const sharedTypes = this._crdtManager.doc.getSharedTypes();
613
+ const sharedTypes = this._crdtManager.doc.get();
619
614
 
620
615
  const storageRoot = Object.entries(sharedTypes).reduce(
621
616
  (acc, [prop, sharedType]) => {
622
- const serialized = sharedType.toJSON();
617
+ const serialized = sharedType.toJson();
623
618
 
624
619
  this._crdtNotifier.subject(prop).next(serialized);
625
620
 
626
621
  return { ...acc, [prop]: serialized };
627
622
  },
628
623
  {} as {
629
- [P in keyof TStorage]: InferYjsSharedTypeJson<TStorage[P]>;
624
+ [P in keyof TStorage]: InferCrdtStorageJson<TStorage[P]>;
630
625
  },
631
626
  );
632
627
 
@@ -643,7 +638,7 @@ export class PluvRoom<
643
638
 
644
639
  this._crdtManager.applyUpdate(updates, this);
645
640
 
646
- const encodedState = this._crdtManager.doc.encodeStateAsUpdate();
641
+ const encodedState = this._crdtManager.doc.getEncodedState();
647
642
 
648
643
  await this._storageStore.flatten(encodedState);
649
644
  },
@@ -708,14 +703,6 @@ export class PluvRoom<
708
703
  }
709
704
  }
710
705
 
711
- private _getTrackedOrigins(): readonly string[] | null {
712
- const connectionId = this._state.connection.id;
713
-
714
- return !connectionId
715
- ? this._trackedOrigins
716
- : [connectionId, ...(this._trackedOrigins ?? [])];
717
- }
718
-
719
706
  private _getWsEndpoint(room: string): string {
720
707
  switch (typeof this._endpoints.wsEndpoint) {
721
708
  case "undefined":
@@ -836,7 +823,7 @@ export class PluvRoom<
836
823
 
837
824
  const update =
838
825
  this._state.connection.count > 1
839
- ? this._crdtManager.doc.encodeStateAsUpdate() ?? null
826
+ ? this._crdtManager.doc.getEncodedState() ?? null
840
827
  : null;
841
828
 
842
829
  this._sendMessage({
@@ -858,25 +845,25 @@ export class PluvRoom<
858
845
  InferIOAuthorize<TIO>
859
846
  >["$STORAGE_RECEIVED"];
860
847
 
861
- const trackedOrigins = this._getTrackedOrigins();
862
-
863
848
  this._crdtManager.initialize({
864
- captureTimeout: this._captureTimeout ?? undefined,
865
- onInitialized: async () => {
849
+ onInitialized: async (update) => {
850
+ this._addToStorageStore(update);
851
+ this._emitSharedTypes();
852
+
866
853
  this._observeCrdt();
854
+ this._stateNotifier.subjects["storage-loaded"].next(true);
867
855
  },
868
856
  origin: ORIGIN_INITIALIZED,
869
- trackedOrigins: trackedOrigins ?? undefined,
870
857
  update: data.state,
871
858
  });
872
859
 
873
- const encodedState = this._crdtManager.doc.encodeStateAsUpdate();
860
+ const encodedState = this._crdtManager.doc.getEncodedState();
874
861
 
875
862
  await this._storageStore.addUpdate(encodedState);
876
863
 
877
864
  this._emitSharedTypes();
878
865
 
879
- const update = this._crdtManager.doc.encodeStateAsUpdate();
866
+ const update = this._crdtManager.doc.getEncodedState();
880
867
 
881
868
  this._sendMessage({
882
869
  type: "$UPDATE_STORAGE",
@@ -897,22 +884,25 @@ export class PluvRoom<
897
884
 
898
885
  if (!this._crdtManager) return;
899
886
 
900
- this._crdtManager.doc.applyUpdate(data.state, ORIGIN_STORAGE_UPDATED);
887
+ this._crdtManager.doc.applyEncodedState({
888
+ origin: ORIGIN_STORAGE_UPDATED,
889
+ update: data.state,
890
+ });
901
891
 
902
- const sharedTypes = this._crdtManager.doc.getSharedTypes();
892
+ const sharedTypes = this._crdtManager.doc.get();
903
893
 
904
894
  const storageRoot = Object.entries(sharedTypes).reduce(
905
895
  (acc, [prop, sharedType]) => {
906
896
  if (!this._crdtManager) return acc;
907
897
 
908
- const serialized = sharedType.toJSON();
898
+ const serialized = sharedType.toJson();
909
899
 
910
900
  this._crdtNotifier.subject(prop).next(serialized);
911
901
 
912
902
  return { ...acc, [prop]: serialized };
913
903
  },
914
904
  {} as {
915
- [P in keyof TStorage]: InferYjsSharedTypeJson<TStorage[P]>;
905
+ [P in keyof TStorage]: InferCrdtStorageJson<TStorage[P]>;
916
906
  },
917
907
  );
918
908
 
@@ -972,27 +962,28 @@ export class PluvRoom<
972
962
 
973
963
  if (!this._crdtManager) return;
974
964
 
975
- const unsubscribe = this._crdtManager.doc.subscribe(
976
- (update, _origin) => {
977
- const origin = _origin ?? null;
965
+ const unsubscribe = this._crdtManager.doc.subscribe((event) => {
966
+ const origin = event.origin ?? null;
978
967
 
979
- this._addToStorageStore(update);
980
- this._emitSharedTypes();
981
-
982
- if (origin === ORIGIN_INITIALIZED || origin === this) return;
968
+ this._addToStorageStore(event.update);
969
+ this._emitSharedTypes();
983
970
 
984
- if (!this._state.webSocket) return;
985
- if (!this._state.connection.id) return;
986
- if (this._state.webSocket.readyState !== WebSocket.OPEN) return;
971
+ if (
972
+ origin === ORIGIN_INITIALIZED ||
973
+ origin === ORIGIN_STORAGE_UPDATED
974
+ ) {
975
+ return;
976
+ }
987
977
 
988
- if (origin === ORIGIN_STORAGE_UPDATED) return;
978
+ if (!this._state.webSocket) return;
979
+ if (!this._state.connection.id) return;
980
+ if (this._state.webSocket.readyState !== WebSocket.OPEN) return;
989
981
 
990
- this._sendMessage({
991
- type: "$UPDATE_STORAGE",
992
- data: { origin, update },
993
- });
994
- },
995
- );
982
+ this._sendMessage({
983
+ type: "$UPDATE_STORAGE",
984
+ data: { origin, update: event.update },
985
+ });
986
+ });
996
987
 
997
988
  this._subscriptions.observeCrdt = unsubscribe;
998
989
  }
@@ -11,17 +11,19 @@ export interface StateNotifierSubjects<
11
11
  "my-presence": Subject<TPresence | null>;
12
12
  myself: Subject<Readonly<Id<UserInfo<TIO>>> | null>;
13
13
  others: Subject<readonly Id<UserInfo<TIO>>[]>;
14
+ "storage-loaded": Subject<boolean>;
14
15
  }
15
16
 
16
17
  type InferSubjectValue<
17
18
  TIO extends IOLike,
18
19
  TPresence extends JsonObject,
19
20
  TSubject extends keyof StateNotifierSubjects<TIO, TPresence>,
20
- > = StateNotifierSubjects<TIO, TPresence>[TSubject] extends Subject<
21
- infer IValue
22
- >
23
- ? Id<IValue>
24
- : never;
21
+ > =
22
+ StateNotifierSubjects<TIO, TPresence>[TSubject] extends Subject<
23
+ infer IValue
24
+ >
25
+ ? Id<IValue>
26
+ : never;
25
27
 
26
28
  export type SubscriptionCallback<
27
29
  TIO extends IOLike,
@@ -38,6 +40,7 @@ export class StateNotifier<
38
40
  "my-presence": makeSubject<TPresence>(),
39
41
  myself: makeSubject<Readonly<Id<UserInfo<TIO>>> | null>(),
40
42
  others: makeSubject<readonly Id<UserInfo<TIO>>[]>(),
43
+ "storage-loaded": makeSubject<true>(),
41
44
  };
42
45
 
43
46
  public subscribe<
package/src/index.ts CHANGED
@@ -1,28 +1,23 @@
1
- export type {
2
- InferYjsSharedTypeJson,
3
- TrackOriginOptions,
4
- } from "@pluv/crdt-yjs";
1
+ export type { AbstractCrdtType, InferCrdtStorageJson } from "@pluv/crdt";
5
2
  export type {
6
3
  BaseUser,
7
4
  EventMessage,
8
5
  EventRecord,
9
6
  IOEventMessage,
10
7
  } from "@pluv/types";
11
- export type { AbstractType } from "yjs";
12
8
  export { AbstractRoom } from "./AbstractRoom";
13
9
  export { AbstractStorageStore } from "./AbstractStorageStore";
14
- export { createClient } from "./createClient";
15
- export type { MockedRoomConfig, MockedRoomEvents } from "./MockedRoom";
16
10
  export { MockedRoom } from "./MockedRoom";
17
- export type { PluvClientOptions } from "./PluvClient";
11
+ export type { MockedRoomConfig, MockedRoomEvents } from "./MockedRoom";
18
12
  export { PluvClient } from "./PluvClient";
13
+ export type { PluvClientOptions } from "./PluvClient";
14
+ export { PluvRoom } from "./PluvRoom";
19
15
  export type {
20
16
  PluvRoomAddon,
21
17
  PluvRoomAddonInput,
22
18
  PluvRoomAddonResult,
23
19
  PluvRoomDebug,
24
20
  } from "./PluvRoom";
25
- export { PluvRoom } from "./PluvRoom";
26
- export type { WebSocketConnection, UserInfo, WebSocketState } from "./types";
21
+ export { createClient } from "./createClient";
27
22
  export { ConnectionState } from "./types";
28
- export * as y from "./y";
23
+ export type { UserInfo, WebSocketConnection, WebSocketState } from "./types";
package/src/y.ts DELETED
@@ -1,9 +0,0 @@
1
- export {
2
- array,
3
- map,
4
- object,
5
- text,
6
- xmlElement,
7
- xmlFragment,
8
- xmlText,
9
- } from "@pluv/crdt-yjs";