@pluv/react 0.28.0 → 0.30.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.
@@ -1,40 +1,151 @@
1
- import type { PluvClient, PluvRouterEventConfig } from "@pluv/client";
2
- import type { CrdtType } from "@pluv/crdt";
3
- import type { IOLike, JsonObject } from "@pluv/types";
4
- import type { FC, ReactNode } from "react";
5
- import { createContext, memo, useContext } from "react";
6
- import type { CreateRoomBundle, CreateRoomBundleOptions } from "./createRoomBundle";
7
- import { createRoomBundle as _createRoomBundle } from "./createRoomBundle";
1
+ import type {
2
+ AbstractRoom,
3
+ CreateRoomOptions,
4
+ MergeEvents,
5
+ MockedRoomEvents,
6
+ PluvClient,
7
+ PluvRoomAddon,
8
+ PluvRoomDebug,
9
+ PluvRouter,
10
+ PluvRouterEventConfig,
11
+ UserInfo,
12
+ WebSocketConnection,
13
+ } from "@pluv/client";
14
+ import { MockedRoom, PluvRoom } from "@pluv/client";
15
+ import type { AbstractCrdtDoc, CrdtType, InferCrdtJson } from "@pluv/crdt";
16
+ import type { Id, InferIOInput, InferIOOutput, IOEventMessage, IOLike, JsonObject } from "@pluv/types";
17
+ import fastDeepEqual from "fast-deep-equal";
18
+ import type { Dispatch, FC, ReactNode } from "react";
19
+ import { createContext, memo, useCallback, useContext, useEffect, useMemo, useState } from "react";
20
+ import { identity, shallowArrayEqual, useRerender, useSyncExternalStoreWithSelector } from "./internal";
8
21
 
9
22
  export interface PluvProviderProps {
10
23
  children?: ReactNode;
11
24
  }
12
25
 
26
+ type BaseRoomProviderProps<TPresence extends JsonObject, TStorage extends Record<string, CrdtType<any, any>>> = {
27
+ children?: ReactNode;
28
+ initialStorage?: keyof TStorage extends never ? never : () => TStorage;
29
+ room: string;
30
+ } & (keyof TPresence extends never ? { initialPresence?: never } : { initialPresence: TPresence });
31
+
32
+ export type MockedRoomProviderProps<
33
+ TIO extends IOLike,
34
+ TPresence extends JsonObject,
35
+ TStorage extends Record<string, CrdtType<any, any>>,
36
+ TEvents extends PluvRouterEventConfig<TIO, TPresence, TStorage> = {},
37
+ > = BaseRoomProviderProps<TPresence, TStorage> & {
38
+ events?: MockedRoomEvents<MergeEvents<TEvents, TIO>>;
39
+ };
40
+
41
+ export type PluvRoomProviderProps<
42
+ TIO extends IOLike,
43
+ TMetadata extends JsonObject,
44
+ TPresence extends JsonObject,
45
+ TStorage extends Record<string, CrdtType<any, any>>,
46
+ > = BaseRoomProviderProps<TPresence, TStorage> & {
47
+ debug?: boolean | PluvRoomDebug<TIO>;
48
+ onAuthorizationFail?: (error: Error) => void;
49
+ } & (keyof TMetadata extends never ? { metadata?: undefined } : { metadata: TMetadata });
50
+
51
+ export interface SubscriptionHookOptions<T extends unknown> {
52
+ isEqual?: (a: T, b: T) => boolean;
53
+ }
54
+
55
+ export type UpdateMyPresenceAction<TPresence extends JsonObject> =
56
+ | Partial<TPresence>
57
+ | ((oldPresence: TPresence | null) => Partial<TPresence>);
58
+
59
+ export type BroadcastProxy<TIO extends IOLike> = (<TEvent extends keyof InferIOInput<TIO>>(
60
+ event: TEvent,
61
+ data: Id<InferIOInput<TIO>[TEvent]>,
62
+ ) => void) & {
63
+ [event in keyof InferIOInput<TIO>]: (input: Id<InferIOInput<TIO>[event]>) => void;
64
+ };
65
+
66
+ export type EventProxy<TIO extends IOLike> = {
67
+ [event in keyof InferIOOutput<TIO>]: {
68
+ useEvent: (callback: (data: Id<IOEventMessage<TIO, event>>) => void) => void;
69
+ };
70
+ };
71
+
13
72
  export interface CreateBundle<
14
73
  TIO extends IOLike,
15
74
  TMetadata extends JsonObject,
16
75
  TPresence extends JsonObject = {},
17
76
  TStorage extends Record<string, CrdtType<any, any>> = {},
77
+ TEvents extends PluvRouterEventConfig<TIO, TPresence, TStorage> = {},
18
78
  > {
19
- // factories
20
- createRoomBundle: <TEvents extends PluvRouterEventConfig<TIO, TPresence, TStorage> = {}>(
21
- options: CreateRoomBundleOptions<TIO, TMetadata, TPresence, TStorage, TEvents>,
22
- ) => CreateRoomBundle<TIO, TMetadata, TPresence, TStorage, TEvents>;
23
-
24
79
  // components
80
+ MockedRoomProvider: FC<MockedRoomProviderProps<TIO, TPresence, TStorage>>;
25
81
  PluvProvider: FC<PluvProviderProps>;
82
+ PluvRoomProvider: FC<PluvRoomProviderProps<TIO, TMetadata, TPresence, TStorage>>;
83
+
84
+ // proxies
85
+ event: EventProxy<MergeEvents<TEvents, TIO>>;
26
86
 
27
87
  // hooks
88
+ useBroadcast: () => BroadcastProxy<MergeEvents<TEvents, TIO>>;
89
+ useCanRedo: () => boolean;
90
+ useCanUndo: () => boolean;
28
91
  useClient: () => PluvClient<TIO, TPresence, TStorage, TMetadata>;
92
+ useConnection: <T extends unknown = WebSocketConnection>(
93
+ selector: (connection: WebSocketConnection) => T,
94
+ options?: SubscriptionHookOptions<Id<T>>,
95
+ ) => Id<T>;
96
+ useDoc: () => AbstractCrdtDoc<TStorage>;
97
+ useEvent: <TType extends keyof InferIOOutput<MergeEvents<TEvents, TIO>>>(
98
+ type: TType,
99
+ callback: (data: Id<IOEventMessage<MergeEvents<TEvents, TIO>, TType>>) => void,
100
+ ) => void;
101
+ useMyPresence: <T extends unknown = TPresence>(
102
+ selector?: (myPresence: TPresence) => T,
103
+ options?: SubscriptionHookOptions<Id<T> | null>,
104
+ ) => [myPresence: Id<T>, updateMyPresence: Dispatch<UpdateMyPresenceAction<TPresence>>];
105
+ useMyself: <T extends unknown = UserInfo<TIO, TPresence>>(
106
+ selector?: (myself: Id<UserInfo<TIO, TPresence>>) => T,
107
+ options?: SubscriptionHookOptions<Id<T> | null>,
108
+ ) => Id<T> | null;
109
+ useOther: <T extends unknown = UserInfo<TIO, TPresence>>(
110
+ connectionId: string,
111
+ selector?: (other: UserInfo<TIO, TPresence>) => T,
112
+ options?: SubscriptionHookOptions<T | null>,
113
+ ) => T | null;
114
+ useOthers: <T extends unknown = readonly UserInfo<TIO, TPresence>[]>(
115
+ selector?: (other: readonly Id<UserInfo<TIO, TPresence>>[]) => T,
116
+ options?: SubscriptionHookOptions<T>,
117
+ ) => T;
118
+ useRedo: () => () => void;
119
+ useRoom: () => AbstractRoom<TIO, TPresence, TStorage>;
120
+ useStorage: <TKey extends keyof TStorage, TData extends unknown = InferCrdtJson<TStorage[TKey]>>(
121
+ key: TKey,
122
+ selector?: (data: InferCrdtJson<TStorage[TKey]>) => TData,
123
+ options?: SubscriptionHookOptions<TData | null>,
124
+ ) => [data: TData | null, sharedType: TStorage[TKey] | null];
125
+ useTransact: () => (fn: (storage: TStorage) => void, origin?: string) => void;
126
+ useUndo: () => () => void;
29
127
  }
30
128
 
129
+ export type CreateBundleOptions<
130
+ TIO extends IOLike,
131
+ TMetadata extends JsonObject = {},
132
+ TPresence extends JsonObject = {},
133
+ TStorage extends Record<string, CrdtType<any, any>> = {},
134
+ TEvents extends PluvRouterEventConfig<TIO, TPresence, TStorage> = {},
135
+ > = {
136
+ addons?: readonly PluvRoomAddon<TIO, TMetadata, TPresence, TStorage>[];
137
+ router?: PluvRouter<TIO, TPresence, TStorage, TEvents>;
138
+ };
139
+
31
140
  export const createBundle = <
32
141
  TIO extends IOLike,
33
142
  TMetadata extends JsonObject = {},
34
143
  TPresence extends JsonObject = {},
35
144
  TStorage extends Record<string, CrdtType<any, any>> = {},
145
+ TEvents extends PluvRouterEventConfig<TIO, TPresence, TStorage> = {},
36
146
  >(
37
147
  client: PluvClient<TIO, TPresence, TStorage, TMetadata>,
148
+ options: CreateBundleOptions<TIO, TMetadata, TPresence, TStorage, TEvents> = {},
38
149
  ): CreateBundle<TIO, TMetadata, TPresence, TStorage> => {
39
150
  /**
40
151
  * !HACK
@@ -45,6 +156,86 @@ export const createBundle = <
45
156
  */
46
157
  const PluvContext = createContext<PluvClient<TIO, TPresence, TStorage, TMetadata>>(null as any);
47
158
 
159
+ /**
160
+ * !HACK
161
+ * @description We'll let the context error out if the room is not provided,
162
+ * and let the users deal with it.
163
+ * @author leedavidcs
164
+ * @date November 11, 2022
165
+ */
166
+ const PluvRoomContext = createContext<AbstractRoom<TIO, TPresence, TStorage>>(null as any);
167
+
168
+ const MockedRoomContext = createContext<{
169
+ room: AbstractRoom<TIO, TPresence, TStorage> | null;
170
+ }>({ room: null });
171
+
172
+ const MockedRoomProvider = memo<MockedRoomProviderProps<TIO, TPresence, TStorage>>((props) => {
173
+ const { children, events, initialPresence, initialStorage, room: _room } = props;
174
+
175
+ const [room] = useState<MockedRoom<TIO, TPresence, TStorage, TEvents>>(() => {
176
+ return new MockedRoom<TIO, TPresence, TStorage, TEvents>(_room, {
177
+ events,
178
+ initialPresence,
179
+ initialStorage:
180
+ typeof initialStorage === "function"
181
+ ? client._defs.initialStorage?.getFactory(initialStorage)
182
+ : client._defs.initialStorage,
183
+ });
184
+ });
185
+
186
+ return (
187
+ <MockedRoomContext.Provider value={{ room }}>
188
+ <PluvRoomContext.Provider value={room}>{children}</PluvRoomContext.Provider>
189
+ </MockedRoomContext.Provider>
190
+ );
191
+ });
192
+
193
+ MockedRoomProvider.displayName = "MockedRoomProvider";
194
+
195
+ const PluvRoomProvider = memo<PluvRoomProviderProps<TIO, TMetadata, TPresence, TStorage>>((props) => {
196
+ const { children, debug, initialPresence, initialStorage, metadata, onAuthorizationFail, room: _room } = props;
197
+
198
+ const rerender = useRerender();
199
+ const { room: mockedRoom } = useContext(MockedRoomContext);
200
+
201
+ const [room] = useState<PluvRoom<TIO, TMetadata, TPresence, TStorage, TEvents>>(() => {
202
+ return client.createRoom(_room, {
203
+ addons: options.addons,
204
+ debug,
205
+ initialPresence,
206
+ initialStorage:
207
+ typeof initialStorage === "function"
208
+ ? client._defs.initialStorage?.getFactory(initialStorage)
209
+ : client._defs.initialStorage,
210
+ metadata,
211
+ onAuthorizationFail,
212
+ router: options.router,
213
+ } as CreateRoomOptions<TIO, TPresence, TStorage, TMetadata, TEvents>);
214
+ });
215
+
216
+ useEffect(() => {
217
+ const unsubscribe = room.subscribe("connection", () => {
218
+ rerender();
219
+ });
220
+
221
+ return () => {
222
+ unsubscribe();
223
+ };
224
+ }, [rerender, room]);
225
+
226
+ useEffect(() => {
227
+ client.enter(room);
228
+
229
+ return () => {
230
+ client.leave(room);
231
+ };
232
+ }, [room]);
233
+
234
+ return <PluvRoomContext.Provider value={mockedRoom ?? room}>{children}</PluvRoomContext.Provider>;
235
+ });
236
+
237
+ PluvRoomProvider.displayName = "PluvRoomProvider";
238
+
48
239
  const PluvProvider = memo<PluvProviderProps>((props) => {
49
240
  const { children } = props;
50
241
 
@@ -55,13 +246,337 @@ export const createBundle = <
55
246
 
56
247
  const useClient = (): PluvClient<TIO, TPresence, TStorage, TMetadata> => useContext(PluvContext);
57
248
 
58
- const createRoomBundle = <TEvents extends PluvRouterEventConfig<TIO, TPresence, TStorage> = {}>(
59
- options: CreateRoomBundleOptions<TIO, TMetadata, TPresence, TStorage, TEvents>,
60
- ): CreateRoomBundle<TIO, TMetadata, TPresence, TStorage, TEvents> => _createRoomBundle(client, options);
249
+ const useRoom = () => useContext(PluvRoomContext);
250
+
251
+ const useBroadcast = (): BroadcastProxy<MergeEvents<TEvents, TIO>> => {
252
+ const room = useRoom();
253
+
254
+ const broadcast = useCallback(
255
+ <TEvent extends keyof InferIOInput<MergeEvents<TEvents, TIO>>>(
256
+ event: TEvent,
257
+ data: Id<InferIOInput<MergeEvents<TEvents, TIO>>[TEvent]>,
258
+ ) => {
259
+ room.broadcast(event, data);
260
+ },
261
+ [room],
262
+ );
263
+
264
+ return useMemo((): BroadcastProxy<MergeEvents<TEvents, TIO>> => {
265
+ return new Proxy(broadcast, {
266
+ get(fn, prop) {
267
+ return (
268
+ data: Id<
269
+ InferIOInput<MergeEvents<TEvents, TIO>>[keyof InferIOInput<MergeEvents<TEvents, TIO>>]
270
+ >,
271
+ ): void => {
272
+ return fn(prop as keyof InferIOInput<MergeEvents<TEvents, TIO>>, data);
273
+ };
274
+ },
275
+ }) as BroadcastProxy<MergeEvents<TEvents, TIO>>;
276
+ }, [broadcast]);
277
+ };
278
+
279
+ const useCanRedo = (): boolean => {
280
+ const room = useRoom();
281
+
282
+ const subscribe = useCallback((onStoreChange: () => void) => room.storageRoot(onStoreChange), [room]);
283
+
284
+ const getSnapshot = useCallback((): boolean => room.canRedo(), [room]);
285
+
286
+ const canRedo = useSyncExternalStoreWithSelector(subscribe, getSnapshot, getSnapshot, identity);
287
+
288
+ return canRedo;
289
+ };
290
+
291
+ const useCanUndo = (): boolean => {
292
+ const room = useRoom();
293
+
294
+ const subscribe = useCallback((onStoreChange: () => void) => room.storageRoot(onStoreChange), [room]);
295
+
296
+ const getSnapshot = useCallback((): boolean => room.canUndo(), [room]);
297
+
298
+ const canUndo = useSyncExternalStoreWithSelector(subscribe, getSnapshot, getSnapshot, identity);
299
+
300
+ return canUndo;
301
+ };
302
+
303
+ const useConnection = <T extends unknown = WebSocketConnection>(
304
+ selector = identity as (connection: WebSocketConnection) => T,
305
+ options?: SubscriptionHookOptions<Id<T>>,
306
+ ): Id<T> => {
307
+ const room = useRoom();
308
+
309
+ const subscribe = useCallback(
310
+ (onStoreChange: () => void) => {
311
+ return room.subscribe("connection", onStoreChange);
312
+ },
313
+ [room],
314
+ );
315
+
316
+ const getSnapshot = room.getConnection;
317
+
318
+ const _selector = useCallback((snapshot: WebSocketConnection) => selector(snapshot) as Id<T>, [selector]);
319
+
320
+ return useSyncExternalStoreWithSelector(
321
+ subscribe,
322
+ getSnapshot,
323
+ getSnapshot,
324
+ _selector,
325
+ options?.isEqual ?? fastDeepEqual,
326
+ );
327
+ };
328
+
329
+ const useDoc = () => {
330
+ const room = useRoom();
331
+
332
+ return room.getDoc();
333
+ };
334
+
335
+ const useEvent = <TType extends keyof InferIOOutput<MergeEvents<TEvents, TIO>>>(
336
+ type: TType,
337
+ callback: (data: Id<IOEventMessage<MergeEvents<TEvents, TIO>, TType>>) => void,
338
+ ): void => {
339
+ const room = useRoom();
340
+
341
+ useEffect(() => {
342
+ const unsubscribe = room.event(type, callback);
343
+
344
+ return () => {
345
+ unsubscribe();
346
+ };
347
+ }, [callback, room, type]);
348
+ };
349
+
350
+ const event = new Proxy(
351
+ {},
352
+ {
353
+ get(_, prop) {
354
+ const useProxyEvent = (
355
+ callback: (
356
+ data: Id<
357
+ IOEventMessage<MergeEvents<TEvents, TIO>, keyof InferIOOutput<MergeEvents<TEvents, TIO>>>
358
+ >,
359
+ ) => void,
360
+ ): void => {
361
+ return useEvent(prop as keyof InferIOOutput<MergeEvents<TEvents, TIO>>, callback);
362
+ };
363
+
364
+ return { useEvent: useProxyEvent };
365
+ },
366
+ },
367
+ ) as EventProxy<MergeEvents<TEvents, TIO>>;
368
+
369
+ const useMyPresence = <T extends unknown = TPresence>(
370
+ selector = identity as (myPresence: TPresence) => T,
371
+ options?: SubscriptionHookOptions<Id<T> | null>,
372
+ ): [Id<T>, Dispatch<UpdateMyPresenceAction<TPresence>>] => {
373
+ const room = useRoom();
374
+
375
+ const subscribe = useCallback(
376
+ (onStoreChange: () => void) => {
377
+ return room.subscribe("my-presence", onStoreChange);
378
+ },
379
+ [room],
380
+ );
381
+
382
+ const getSnapshot = room.getMyPresence;
383
+
384
+ const _selector = useCallback((snapshot: TPresence) => selector(snapshot) as Id<T>, [selector]);
385
+
386
+ const myPresence = useSyncExternalStoreWithSelector(
387
+ subscribe,
388
+ getSnapshot,
389
+ getSnapshot,
390
+ _selector,
391
+ options?.isEqual ?? fastDeepEqual,
392
+ );
393
+
394
+ return [myPresence, room.updateMyPresence];
395
+ };
396
+
397
+ const useMyself = <T extends unknown = UserInfo<TIO, TPresence>>(
398
+ selector = identity as (myself: Id<UserInfo<TIO, TPresence>>) => T,
399
+ options?: SubscriptionHookOptions<Id<T> | null>,
400
+ ): Id<T> | null => {
401
+ const room = useRoom();
402
+
403
+ const subscribe = useCallback(
404
+ (onStoreChange: () => void) => {
405
+ return room.subscribe("myself", onStoreChange);
406
+ },
407
+ [room],
408
+ );
409
+
410
+ const getSnapshot = room.getMyself;
411
+
412
+ const _selector = useCallback(
413
+ (snapshot: Id<UserInfo<TIO, TPresence>> | null) => {
414
+ return !snapshot ? null : (selector(snapshot) as Id<T>);
415
+ },
416
+ [selector],
417
+ );
418
+
419
+ return useSyncExternalStoreWithSelector(
420
+ subscribe,
421
+ getSnapshot,
422
+ getSnapshot,
423
+ _selector,
424
+ options?.isEqual ?? fastDeepEqual,
425
+ );
426
+ };
427
+
428
+ const useOther = <T extends unknown = UserInfo<TIO, TPresence>>(
429
+ connectionId: string,
430
+ selector = identity as (other: UserInfo<TIO, TPresence>) => T,
431
+ options?: SubscriptionHookOptions<T | null>,
432
+ ): T | null => {
433
+ const room = useRoom();
434
+
435
+ const subscribe = useCallback(
436
+ (onStoreChange: () => void) => {
437
+ return room.other(connectionId, onStoreChange);
438
+ },
439
+ [room, connectionId],
440
+ );
441
+
442
+ const getSnapshot = useCallback(() => room.getOther(connectionId), [room, connectionId]);
443
+
444
+ const _selector = useCallback(
445
+ (snapshot: Id<UserInfo<TIO, TPresence>> | null) => {
446
+ return !snapshot ? null : (selector(snapshot) as T);
447
+ },
448
+ [selector],
449
+ );
450
+
451
+ return useSyncExternalStoreWithSelector(
452
+ subscribe,
453
+ getSnapshot,
454
+ getSnapshot,
455
+ _selector,
456
+ options?.isEqual ?? fastDeepEqual,
457
+ );
458
+ };
459
+
460
+ const useOthers = <T extends unknown = readonly UserInfo<TIO, TPresence>[]>(
461
+ selector = identity as (other: readonly Id<UserInfo<TIO, TPresence>>[]) => T,
462
+ options?: SubscriptionHookOptions<T>,
463
+ ): T => {
464
+ const room = useRoom();
465
+
466
+ const subscribe = useCallback(
467
+ (onStoreChange: () => void) => {
468
+ return room.subscribe("others", onStoreChange);
469
+ },
470
+ [room],
471
+ );
472
+
473
+ const getSnapshot = room.getOthers;
474
+
475
+ return useSyncExternalStoreWithSelector(
476
+ subscribe,
477
+ getSnapshot,
478
+ getSnapshot,
479
+ selector as (other: readonly Id<UserInfo<TIO, TPresence>>[]) => T,
480
+ options?.isEqual ??
481
+ ((a, b) => {
482
+ /**
483
+ * !HACK
484
+ * @description Assume the return type will always be an array when this occurs
485
+ * and do a shallow comparison instead like how standard React dependency
486
+ * arrays work. This is for performance's sake and may lead to bugs if the
487
+ * selector doesn't always return an array
488
+ * @date June 22, 2024
489
+ */
490
+ if (Array.isArray(a) && Array.isArray(b) && a.length === b.length) {
491
+ return shallowArrayEqual(a, b);
492
+ }
493
+
494
+ return fastDeepEqual(a, b);
495
+ }),
496
+ );
497
+ };
498
+
499
+ const useRedo = () => {
500
+ const room = useRoom();
501
+
502
+ return room.redo;
503
+ };
504
+
505
+ const useStorage = <TKey extends keyof TStorage, TData extends unknown = InferCrdtJson<TStorage[TKey]>>(
506
+ key: TKey,
507
+ selector = identity as (data: InferCrdtJson<TStorage[TKey]>) => TData,
508
+ options?: SubscriptionHookOptions<TData | null>,
509
+ ): [data: TData | null, sharedType: TStorage[TKey] | null] => {
510
+ const room = useRoom();
511
+ const rerender = useRerender();
512
+
513
+ room.subscribe("storage-loaded", () => {
514
+ rerender();
515
+ });
516
+
517
+ const subscribe = useCallback((onStoreChange: () => void) => room.storage(key, onStoreChange), [key, room]);
518
+
519
+ const getSnapshot = useCallback((): InferCrdtJson<TStorage[TKey]> | null => {
520
+ return room.getStorageJson(key);
521
+ }, [key, room]);
522
+
523
+ const _selector = useCallback(
524
+ (snapshot: InferCrdtJson<TStorage[TKey]> | null) => {
525
+ return snapshot === null ? null : selector(snapshot);
526
+ },
527
+ [selector],
528
+ );
529
+
530
+ const data = useSyncExternalStoreWithSelector(
531
+ subscribe,
532
+ getSnapshot,
533
+ getSnapshot,
534
+ _selector,
535
+ options?.isEqual ?? fastDeepEqual,
536
+ );
537
+
538
+ const sharedType = room.getStorage(key) ?? null;
539
+
540
+ return [data, sharedType];
541
+ };
542
+
543
+ const useTransact = () => {
544
+ const room = useRoom();
545
+
546
+ return room.transact;
547
+ };
548
+
549
+ const useUndo = () => {
550
+ const room = useRoom();
551
+
552
+ return room.undo;
553
+ };
61
554
 
62
555
  return {
63
- createRoomBundle,
556
+ // components
557
+ MockedRoomProvider,
64
558
  PluvProvider,
559
+ PluvRoomProvider,
560
+
561
+ // proxies
562
+ event,
563
+
564
+ // hooks
565
+ useBroadcast,
566
+ useCanRedo,
567
+ useCanUndo,
65
568
  useClient,
569
+ useConnection,
570
+ useDoc,
571
+ useEvent,
572
+ useMyPresence,
573
+ useMyself,
574
+ useOther,
575
+ useOthers,
576
+ useRedo,
577
+ useRoom,
578
+ useStorage,
579
+ useTransact,
580
+ useUndo,
66
581
  };
67
582
  };
package/src/index.ts CHANGED
@@ -2,11 +2,4 @@ export { ConnectionState, createClient } from "@pluv/client";
2
2
  export type { CrdtType, InferCrdtJson } from "@pluv/crdt";
3
3
  export type { BaseUser, EventMessage, EventRecord, IOEventMessage } from "@pluv/types";
4
4
  export { createBundle } from "./createBundle";
5
- export type { CreateBundle, PluvProviderProps } from "./createBundle";
6
- export type {
7
- CreateRoomBundle,
8
- CreateRoomBundleOptions,
9
- InferRoomStorage,
10
- PluvRoomProviderProps,
11
- SubscriptionHookOptions,
12
- } from "./createRoomBundle";
5
+ export type { CreateBundle, PluvProviderProps, PluvRoomProviderProps, SubscriptionHookOptions } from "./createBundle";