@pluv/client 0.15.0 → 0.16.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/.turbo/turbo-build.log +9 -9
- package/CHANGELOG.md +182 -37
- package/README.md +9 -12
- package/dist/index.d.mts +65 -77
- package/dist/index.d.ts +65 -77
- package/dist/index.js +271 -303
- package/dist/index.mjs +270 -313
- package/package.json +7 -11
- package/src/AbstractRoom.ts +13 -8
- package/src/CrdtManager.ts +55 -57
- package/src/CrdtNotifier.ts +12 -12
- package/src/MockedRoom.ts +44 -40
- package/src/OtherNotifier.ts +1 -1
- package/src/PluvClient.ts +4 -4
- package/src/PluvRoom.ts +67 -76
- package/src/StateNotifier.ts +8 -5
- package/src/index.ts +6 -11
- package/src/y.ts +0 -9
package/src/PluvRoom.ts
CHANGED
|
@@ -1,18 +1,21 @@
|
|
|
1
|
-
import {
|
|
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,
|
|
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,
|
|
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,
|
|
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,
|
|
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,
|
|
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,
|
|
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
|
-
|
|
247
|
-
this.
|
|
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():
|
|
368
|
-
return this._crdtManager.doc
|
|
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:
|
|
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]:
|
|
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
|
-
|
|
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.
|
|
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.
|
|
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]:
|
|
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.
|
|
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.
|
|
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
|
-
|
|
865
|
-
|
|
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.
|
|
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.
|
|
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.
|
|
887
|
+
this._crdtManager.doc.applyEncodedState({
|
|
888
|
+
origin: ORIGIN_STORAGE_UPDATED,
|
|
889
|
+
update: data.state,
|
|
890
|
+
});
|
|
901
891
|
|
|
902
|
-
const sharedTypes = this._crdtManager.doc.
|
|
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.
|
|
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]:
|
|
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
|
-
|
|
977
|
-
const origin = _origin ?? null;
|
|
965
|
+
const unsubscribe = this._crdtManager.doc.subscribe((event) => {
|
|
966
|
+
const origin = event.origin ?? null;
|
|
978
967
|
|
|
979
|
-
|
|
980
|
-
|
|
981
|
-
|
|
982
|
-
if (origin === ORIGIN_INITIALIZED || origin === this) return;
|
|
968
|
+
this._addToStorageStore(event.update);
|
|
969
|
+
this._emitSharedTypes();
|
|
983
970
|
|
|
984
|
-
|
|
985
|
-
|
|
986
|
-
|
|
971
|
+
if (
|
|
972
|
+
origin === ORIGIN_INITIALIZED ||
|
|
973
|
+
origin === ORIGIN_STORAGE_UPDATED
|
|
974
|
+
) {
|
|
975
|
+
return;
|
|
976
|
+
}
|
|
987
977
|
|
|
988
|
-
|
|
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
|
-
|
|
991
|
-
|
|
992
|
-
|
|
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
|
}
|
package/src/StateNotifier.ts
CHANGED
|
@@ -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
|
-
> =
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
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 {
|
|
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 {
|
|
26
|
-
export type { WebSocketConnection, UserInfo, WebSocketState } from "./types";
|
|
21
|
+
export { createClient } from "./createClient";
|
|
27
22
|
export { ConnectionState } from "./types";
|
|
28
|
-
export
|
|
23
|
+
export type { UserInfo, WebSocketConnection, WebSocketState } from "./types";
|