@pluv/react 0.26.0 → 0.28.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 +132 -0
- package/dist/index.d.mts +16 -17
- package/dist/index.d.ts +16 -17
- package/dist/index.js +18 -20
- package/dist/index.mjs +18 -20
- package/package.json +9 -9
- package/src/createBundle.tsx +24 -17
- package/src/createRoomBundle.tsx +54 -37
- package/src/internal/hooks/useSyncExternalStoreWithSelector.ts +2 -2
- package/src/internal/index.ts +1 -1
package/.turbo/turbo-build.log
CHANGED
|
@@ -1,18 +1,18 @@
|
|
|
1
1
|
|
|
2
|
-
> @pluv/react@0.
|
|
2
|
+
> @pluv/react@0.28.0 build /home/runner/work/pluv/pluv/packages/react
|
|
3
3
|
> tsup src/index.ts --format esm,cjs --dts --external react
|
|
4
4
|
|
|
5
5
|
[34mCLI[39m Building entry: src/index.ts
|
|
6
6
|
[34mCLI[39m Using tsconfig: tsconfig.json
|
|
7
|
-
[34mCLI[39m tsup v8.
|
|
7
|
+
[34mCLI[39m tsup v8.3.0
|
|
8
8
|
[34mCLI[39m Target: es6
|
|
9
9
|
[34mESM[39m Build start
|
|
10
10
|
[34mCJS[39m Build start
|
|
11
|
-
[
|
|
12
|
-
[
|
|
13
|
-
[
|
|
14
|
-
[
|
|
11
|
+
[32mESM[39m [1mdist/index.mjs [22m[32m11.84 KB[39m
|
|
12
|
+
[32mESM[39m ⚡️ Build success in 141ms
|
|
13
|
+
[32mCJS[39m [1mdist/index.js [22m[32m14.23 KB[39m
|
|
14
|
+
[32mCJS[39m ⚡️ Build success in 141ms
|
|
15
15
|
[34mDTS[39m Build start
|
|
16
|
-
[32mDTS[39m ⚡️ Build success in
|
|
17
|
-
[32mDTS[39m [1mdist/index.d.mts [22m[
|
|
18
|
-
[32mDTS[39m [1mdist/index.d.ts [22m[
|
|
16
|
+
[32mDTS[39m ⚡️ Build success in 4997ms
|
|
17
|
+
[32mDTS[39m [1mdist/index.d.mts [22m[32m6.04 KB[39m
|
|
18
|
+
[32mDTS[39m [1mdist/index.d.ts [22m[32m6.04 KB[39m
|
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,137 @@
|
|
|
1
1
|
# @pluv/react
|
|
2
2
|
|
|
3
|
+
## 0.28.0
|
|
4
|
+
|
|
5
|
+
### Minor Changes
|
|
6
|
+
|
|
7
|
+
- 778b43e: Remove the `initialStorage` option from `createRoomBundle`. This has been moved to `createClient`.
|
|
8
|
+
|
|
9
|
+
### Patch Changes
|
|
10
|
+
|
|
11
|
+
- @pluv/client@0.28.0
|
|
12
|
+
- @pluv/crdt@0.28.0
|
|
13
|
+
- @pluv/types@0.28.0
|
|
14
|
+
|
|
15
|
+
## 0.27.0
|
|
16
|
+
|
|
17
|
+
### Minor Changes
|
|
18
|
+
|
|
19
|
+
- 19ed36c: Updated `createClient` and `createRoomBundle` object params to better support automatic type inference.
|
|
20
|
+
|
|
21
|
+
```ts
|
|
22
|
+
// Before
|
|
23
|
+
import { createClient } from "@pluv/react";
|
|
24
|
+
import { yjs } from "@pluv/crdt-yjs";
|
|
25
|
+
import { z } from "zod";
|
|
26
|
+
import type { ioServer } from "./server/ioServer";
|
|
27
|
+
|
|
28
|
+
const client = createClient<typeof ioServer>({
|
|
29
|
+
authEndpoint: ({ room }) => "MY_AUTH_URL",
|
|
30
|
+
wsEndpoint: ({ room }) => "MY_WEBSOCKET_URL",
|
|
31
|
+
});
|
|
32
|
+
|
|
33
|
+
client.createRoom("my-example-room", {
|
|
34
|
+
presence: z.object({
|
|
35
|
+
selectionId: z.string().nullish(),
|
|
36
|
+
}),
|
|
37
|
+
initialPresence: {
|
|
38
|
+
selectionId: null,
|
|
39
|
+
},
|
|
40
|
+
initialStorage: yjs.doc(() => ({
|
|
41
|
+
messages: yjs.array<string>([]),
|
|
42
|
+
})),
|
|
43
|
+
});
|
|
44
|
+
|
|
45
|
+
// After
|
|
46
|
+
|
|
47
|
+
import { createBundle, createClient } from "@pluv/react";
|
|
48
|
+
|
|
49
|
+
const client = createClient({
|
|
50
|
+
authEndpoint: ({ room }) => "MY_AUTH_URL",
|
|
51
|
+
wsEndpoint: ({ room }) => "MY_WEBSOCKET_URL",
|
|
52
|
+
/**
|
|
53
|
+
* @description The ioServer type now needs to be inferred on this property
|
|
54
|
+
* instead of within the generic on `createClient`. This is because of
|
|
55
|
+
* limitations with TypeScript not yet supporting partial type-inference
|
|
56
|
+
* for generics. Ensure to no-loonger include any generics on `createClient`
|
|
57
|
+
*/
|
|
58
|
+
infer: (i) => ({ io: i<typeof ioServer> }),
|
|
59
|
+
// Now moved to `createClient` from `PluvClient.createRoom`
|
|
60
|
+
presence: z.object({
|
|
61
|
+
selectionId: z.string().nullish(),
|
|
62
|
+
}),
|
|
63
|
+
/**
|
|
64
|
+
* @description Now added to `createClient` to specify defaults for all
|
|
65
|
+
* rooms, and to infer types for storage. This value will be overwritten by
|
|
66
|
+
* `PluvClient.createRoom`.
|
|
67
|
+
*/
|
|
68
|
+
initialStorage: yjs.doc(() => ({
|
|
69
|
+
messages: yjs.array<string>([]),
|
|
70
|
+
})),
|
|
71
|
+
});
|
|
72
|
+
|
|
73
|
+
const { createRoomBundle } = createBundle(client);
|
|
74
|
+
const pluv = createRoomBundle({});
|
|
75
|
+
```
|
|
76
|
+
|
|
77
|
+
### Patch Changes
|
|
78
|
+
|
|
79
|
+
- 19ed36c: Added client-side event router. This more-or-less mirrors the server-side event router. You can use both the server-side and client-side router simultaneously, but you should generally prefer only using one or the other.
|
|
80
|
+
|
|
81
|
+
```ts
|
|
82
|
+
// Backend Server
|
|
83
|
+
import { createIO } from "@pluv/io";
|
|
84
|
+
|
|
85
|
+
const io = createIO({ /* ... */ });
|
|
86
|
+
const ioServer = io.server({
|
|
87
|
+
router: io.router({
|
|
88
|
+
multiply2: io.procedure
|
|
89
|
+
.input(z.object({ value: z.number() }))
|
|
90
|
+
.broadcast(({ value }) => ({
|
|
91
|
+
multiplied2: { value: value * 2 },
|
|
92
|
+
})),
|
|
93
|
+
}),
|
|
94
|
+
});
|
|
95
|
+
|
|
96
|
+
// Frontend Client
|
|
97
|
+
import { createBundle createClient } from "@pluv/react";
|
|
98
|
+
|
|
99
|
+
const io = createClient({ /* ... */ });
|
|
100
|
+
|
|
101
|
+
const { createRoomBundle } = createBundle(io);
|
|
102
|
+
const pluv = createRoomBundle({
|
|
103
|
+
// ...
|
|
104
|
+
router: io.router({
|
|
105
|
+
add5: io.procedure
|
|
106
|
+
.input(z.object({ value: z.number() }))
|
|
107
|
+
.broadcast(({ value }) => ({
|
|
108
|
+
/**
|
|
109
|
+
* @description Because `ioServer` does not specify `added5`,
|
|
110
|
+
* this will be forwarded to connected peers.
|
|
111
|
+
*/
|
|
112
|
+
added5: { value: value + 5 },
|
|
113
|
+
})),
|
|
114
|
+
/**
|
|
115
|
+
* @description This is possible, but not recommended to do. Because
|
|
116
|
+
* `multiply2` is a procedure on `ioServer`, this will trigger the
|
|
117
|
+
* `multiply2` procedure on `ioServer`. Connected peers will not
|
|
118
|
+
* receive `multiply2`, but rather `multipled2`.
|
|
119
|
+
*/
|
|
120
|
+
subtract5Multiply2: io.procedure
|
|
121
|
+
.input(z.object({ value: z.number() }))
|
|
122
|
+
.broadcast(({ value }) => ({
|
|
123
|
+
multiply2: { value: value - 5 },
|
|
124
|
+
})),
|
|
125
|
+
}),
|
|
126
|
+
});
|
|
127
|
+
```
|
|
128
|
+
|
|
129
|
+
- Updated dependencies [19ed36c]
|
|
130
|
+
- Updated dependencies [19ed36c]
|
|
131
|
+
- @pluv/client@0.27.0
|
|
132
|
+
- @pluv/crdt@0.27.0
|
|
133
|
+
- @pluv/types@0.27.0
|
|
134
|
+
|
|
3
135
|
## 0.26.0
|
|
4
136
|
|
|
5
137
|
### Minor Changes
|
package/dist/index.d.mts
CHANGED
|
@@ -1,15 +1,14 @@
|
|
|
1
|
-
import { PluvRoomAddon, PluvRoomDebug, WebSocketConnection, UserInfo, AbstractRoom, MockedRoomEvents, PluvClient } from '@pluv/client';
|
|
1
|
+
import { PluvRouterEventConfig, PluvRoomAddon, PluvRouter, PluvRoomDebug, MergeEvents, WebSocketConnection, UserInfo, AbstractRoom, MockedRoomEvents, PluvClient } from '@pluv/client';
|
|
2
2
|
export { ConnectionState, createClient } from '@pluv/client';
|
|
3
|
-
import { CrdtType,
|
|
3
|
+
import { CrdtType, AbstractCrdtDoc, InferCrdtJson } from '@pluv/crdt';
|
|
4
4
|
export { CrdtType, InferCrdtJson } from '@pluv/crdt';
|
|
5
|
-
import { IOLike, JsonObject,
|
|
5
|
+
import { IOLike, JsonObject, Id, InferIOOutput, IOEventMessage, InferIOInput } from '@pluv/types';
|
|
6
6
|
export { BaseUser, EventMessage, EventRecord, IOEventMessage } from '@pluv/types';
|
|
7
7
|
import { FC, Dispatch, ReactNode } from 'react';
|
|
8
8
|
|
|
9
|
-
type CreateRoomBundleOptions<TIO extends IOLike, TMetadata extends JsonObject = {}, TPresence extends JsonObject = {}, TStorage extends Record<string, CrdtType<any, any>> = {}> = {
|
|
9
|
+
type CreateRoomBundleOptions<TIO extends IOLike, TMetadata extends JsonObject = {}, TPresence extends JsonObject = {}, TStorage extends Record<string, CrdtType<any, any>> = {}, TEvents extends PluvRouterEventConfig<TIO, TPresence, TStorage> = {}> = {
|
|
10
10
|
addons?: readonly PluvRoomAddon<TIO, TMetadata, TPresence, TStorage>[];
|
|
11
|
-
|
|
12
|
-
presence?: InputZodLike<TPresence>;
|
|
11
|
+
router?: PluvRouter<TIO, TPresence, TStorage, TEvents>;
|
|
13
12
|
};
|
|
14
13
|
type BaseRoomProviderProps<TPresence extends JsonObject, TStorage extends Record<string, CrdtType<any, any>>> = {
|
|
15
14
|
children?: ReactNode;
|
|
@@ -20,8 +19,8 @@ type BaseRoomProviderProps<TPresence extends JsonObject, TStorage extends Record
|
|
|
20
19
|
} : {
|
|
21
20
|
initialPresence: TPresence;
|
|
22
21
|
});
|
|
23
|
-
type MockedRoomProviderProps<TIO extends IOLike, TPresence extends JsonObject, TStorage extends Record<string, CrdtType<any, any
|
|
24
|
-
events?: MockedRoomEvents<TIO
|
|
22
|
+
type MockedRoomProviderProps<TIO extends IOLike, TPresence extends JsonObject, TStorage extends Record<string, CrdtType<any, any>>, TEvents extends PluvRouterEventConfig<TIO, TPresence, TStorage> = {}> = BaseRoomProviderProps<TPresence, TStorage> & {
|
|
23
|
+
events?: MockedRoomEvents<MergeEvents<TEvents, TIO>>;
|
|
25
24
|
};
|
|
26
25
|
type PluvRoomProviderProps<TIO extends IOLike, TMetadata extends JsonObject, TPresence extends JsonObject, TStorage extends Record<string, CrdtType<any, any>>> = BaseRoomProviderProps<TPresence, TStorage> & {
|
|
27
26
|
debug?: boolean | PluvRoomDebug<TIO>;
|
|
@@ -43,16 +42,16 @@ type EventProxy<TIO extends IOLike> = {
|
|
|
43
42
|
useEvent: (callback: (data: Id<IOEventMessage<TIO, event>>) => void) => void;
|
|
44
43
|
};
|
|
45
44
|
};
|
|
46
|
-
interface CreateRoomBundle<TIO extends IOLike, TMetadata extends JsonObject, TPresence extends JsonObject, TStorage extends Record<string, CrdtType<any, any
|
|
45
|
+
interface CreateRoomBundle<TIO extends IOLike, TMetadata extends JsonObject, TPresence extends JsonObject, TStorage extends Record<string, CrdtType<any, any>>, TEvents extends PluvRouterEventConfig<TIO, TPresence, TStorage> = {}> {
|
|
47
46
|
MockedRoomProvider: FC<MockedRoomProviderProps<TIO, TPresence, TStorage>>;
|
|
48
47
|
PluvRoomProvider: FC<PluvRoomProviderProps<TIO, TMetadata, TPresence, TStorage>>;
|
|
49
|
-
event: EventProxy<TIO
|
|
50
|
-
useBroadcast: () => BroadcastProxy<TIO
|
|
48
|
+
event: EventProxy<MergeEvents<TEvents, TIO>>;
|
|
49
|
+
useBroadcast: () => BroadcastProxy<MergeEvents<TEvents, TIO>>;
|
|
51
50
|
useCanRedo: () => boolean;
|
|
52
51
|
useCanUndo: () => boolean;
|
|
53
52
|
useConnection: <T extends unknown = WebSocketConnection>(selector: (connection: WebSocketConnection) => T, options?: SubscriptionHookOptions<Id<T>>) => Id<T>;
|
|
54
53
|
useDoc: () => AbstractCrdtDoc<TStorage>;
|
|
55
|
-
useEvent: <TType extends keyof InferIOOutput<TIO
|
|
54
|
+
useEvent: <TType extends keyof InferIOOutput<MergeEvents<TEvents, TIO>>>(type: TType, callback: (data: Id<IOEventMessage<MergeEvents<TEvents, TIO>, TType>>) => void) => void;
|
|
56
55
|
useMyPresence: <T extends unknown = TPresence>(selector?: (myPresence: TPresence) => T, options?: SubscriptionHookOptions<Id<T> | null>) => [myPresence: Id<T>, updateMyPresence: Dispatch<UpdateMyPresenceAction<TPresence>>];
|
|
57
56
|
useMyself: <T extends unknown = UserInfo<TIO, TPresence>>(selector?: (myself: Id<UserInfo<TIO, TPresence>>) => T, options?: SubscriptionHookOptions<Id<T> | null>) => Id<T> | null;
|
|
58
57
|
useOther: <T extends unknown = UserInfo<TIO, TPresence>>(connectionId: string, selector?: (other: UserInfo<TIO, TPresence>) => T, options?: SubscriptionHookOptions<T | null>) => T | null;
|
|
@@ -63,16 +62,16 @@ interface CreateRoomBundle<TIO extends IOLike, TMetadata extends JsonObject, TPr
|
|
|
63
62
|
useTransact: () => (fn: (storage: TStorage) => void, origin?: string) => void;
|
|
64
63
|
useUndo: () => () => void;
|
|
65
64
|
}
|
|
66
|
-
type InferRoomStorage<TRoomBundle extends CreateRoomBundle<any, any, any, any>> = TRoomBundle extends CreateRoomBundle<any, any, any, infer IStorage> ? IStorage : never;
|
|
65
|
+
type InferRoomStorage<TRoomBundle extends CreateRoomBundle<any, any, any, any, any>> = TRoomBundle extends CreateRoomBundle<any, any, any, infer IStorage> ? IStorage : never;
|
|
67
66
|
|
|
68
67
|
interface PluvProviderProps {
|
|
69
68
|
children?: ReactNode;
|
|
70
69
|
}
|
|
71
|
-
interface CreateBundle<TIO extends IOLike, TMetadata extends JsonObject> {
|
|
72
|
-
createRoomBundle: <
|
|
70
|
+
interface CreateBundle<TIO extends IOLike, TMetadata extends JsonObject, TPresence extends JsonObject = {}, TStorage extends Record<string, CrdtType<any, any>> = {}> {
|
|
71
|
+
createRoomBundle: <TEvents extends PluvRouterEventConfig<TIO, TPresence, TStorage> = {}>(options: CreateRoomBundleOptions<TIO, TMetadata, TPresence, TStorage, TEvents>) => CreateRoomBundle<TIO, TMetadata, TPresence, TStorage, TEvents>;
|
|
73
72
|
PluvProvider: FC<PluvProviderProps>;
|
|
74
|
-
useClient: () => PluvClient<TIO, TMetadata>;
|
|
73
|
+
useClient: () => PluvClient<TIO, TPresence, TStorage, TMetadata>;
|
|
75
74
|
}
|
|
76
|
-
declare const createBundle: <TIO extends IOLike, TMetadata extends JsonObject>(client: PluvClient<TIO, TMetadata>) => CreateBundle<TIO, TMetadata>;
|
|
75
|
+
declare const createBundle: <TIO extends IOLike, TMetadata extends JsonObject = {}, TPresence extends JsonObject = {}, TStorage extends Record<string, CrdtType<any, any>> = {}>(client: PluvClient<TIO, TPresence, TStorage, TMetadata>) => CreateBundle<TIO, TMetadata, TPresence, TStorage>;
|
|
77
76
|
|
|
78
77
|
export { type CreateBundle, type CreateRoomBundle, type CreateRoomBundleOptions, type InferRoomStorage, type PluvProviderProps, type PluvRoomProviderProps, type SubscriptionHookOptions, createBundle };
|
package/dist/index.d.ts
CHANGED
|
@@ -1,15 +1,14 @@
|
|
|
1
|
-
import { PluvRoomAddon, PluvRoomDebug, WebSocketConnection, UserInfo, AbstractRoom, MockedRoomEvents, PluvClient } from '@pluv/client';
|
|
1
|
+
import { PluvRouterEventConfig, PluvRoomAddon, PluvRouter, PluvRoomDebug, MergeEvents, WebSocketConnection, UserInfo, AbstractRoom, MockedRoomEvents, PluvClient } from '@pluv/client';
|
|
2
2
|
export { ConnectionState, createClient } from '@pluv/client';
|
|
3
|
-
import { CrdtType,
|
|
3
|
+
import { CrdtType, AbstractCrdtDoc, InferCrdtJson } from '@pluv/crdt';
|
|
4
4
|
export { CrdtType, InferCrdtJson } from '@pluv/crdt';
|
|
5
|
-
import { IOLike, JsonObject,
|
|
5
|
+
import { IOLike, JsonObject, Id, InferIOOutput, IOEventMessage, InferIOInput } from '@pluv/types';
|
|
6
6
|
export { BaseUser, EventMessage, EventRecord, IOEventMessage } from '@pluv/types';
|
|
7
7
|
import { FC, Dispatch, ReactNode } from 'react';
|
|
8
8
|
|
|
9
|
-
type CreateRoomBundleOptions<TIO extends IOLike, TMetadata extends JsonObject = {}, TPresence extends JsonObject = {}, TStorage extends Record<string, CrdtType<any, any>> = {}> = {
|
|
9
|
+
type CreateRoomBundleOptions<TIO extends IOLike, TMetadata extends JsonObject = {}, TPresence extends JsonObject = {}, TStorage extends Record<string, CrdtType<any, any>> = {}, TEvents extends PluvRouterEventConfig<TIO, TPresence, TStorage> = {}> = {
|
|
10
10
|
addons?: readonly PluvRoomAddon<TIO, TMetadata, TPresence, TStorage>[];
|
|
11
|
-
|
|
12
|
-
presence?: InputZodLike<TPresence>;
|
|
11
|
+
router?: PluvRouter<TIO, TPresence, TStorage, TEvents>;
|
|
13
12
|
};
|
|
14
13
|
type BaseRoomProviderProps<TPresence extends JsonObject, TStorage extends Record<string, CrdtType<any, any>>> = {
|
|
15
14
|
children?: ReactNode;
|
|
@@ -20,8 +19,8 @@ type BaseRoomProviderProps<TPresence extends JsonObject, TStorage extends Record
|
|
|
20
19
|
} : {
|
|
21
20
|
initialPresence: TPresence;
|
|
22
21
|
});
|
|
23
|
-
type MockedRoomProviderProps<TIO extends IOLike, TPresence extends JsonObject, TStorage extends Record<string, CrdtType<any, any
|
|
24
|
-
events?: MockedRoomEvents<TIO
|
|
22
|
+
type MockedRoomProviderProps<TIO extends IOLike, TPresence extends JsonObject, TStorage extends Record<string, CrdtType<any, any>>, TEvents extends PluvRouterEventConfig<TIO, TPresence, TStorage> = {}> = BaseRoomProviderProps<TPresence, TStorage> & {
|
|
23
|
+
events?: MockedRoomEvents<MergeEvents<TEvents, TIO>>;
|
|
25
24
|
};
|
|
26
25
|
type PluvRoomProviderProps<TIO extends IOLike, TMetadata extends JsonObject, TPresence extends JsonObject, TStorage extends Record<string, CrdtType<any, any>>> = BaseRoomProviderProps<TPresence, TStorage> & {
|
|
27
26
|
debug?: boolean | PluvRoomDebug<TIO>;
|
|
@@ -43,16 +42,16 @@ type EventProxy<TIO extends IOLike> = {
|
|
|
43
42
|
useEvent: (callback: (data: Id<IOEventMessage<TIO, event>>) => void) => void;
|
|
44
43
|
};
|
|
45
44
|
};
|
|
46
|
-
interface CreateRoomBundle<TIO extends IOLike, TMetadata extends JsonObject, TPresence extends JsonObject, TStorage extends Record<string, CrdtType<any, any
|
|
45
|
+
interface CreateRoomBundle<TIO extends IOLike, TMetadata extends JsonObject, TPresence extends JsonObject, TStorage extends Record<string, CrdtType<any, any>>, TEvents extends PluvRouterEventConfig<TIO, TPresence, TStorage> = {}> {
|
|
47
46
|
MockedRoomProvider: FC<MockedRoomProviderProps<TIO, TPresence, TStorage>>;
|
|
48
47
|
PluvRoomProvider: FC<PluvRoomProviderProps<TIO, TMetadata, TPresence, TStorage>>;
|
|
49
|
-
event: EventProxy<TIO
|
|
50
|
-
useBroadcast: () => BroadcastProxy<TIO
|
|
48
|
+
event: EventProxy<MergeEvents<TEvents, TIO>>;
|
|
49
|
+
useBroadcast: () => BroadcastProxy<MergeEvents<TEvents, TIO>>;
|
|
51
50
|
useCanRedo: () => boolean;
|
|
52
51
|
useCanUndo: () => boolean;
|
|
53
52
|
useConnection: <T extends unknown = WebSocketConnection>(selector: (connection: WebSocketConnection) => T, options?: SubscriptionHookOptions<Id<T>>) => Id<T>;
|
|
54
53
|
useDoc: () => AbstractCrdtDoc<TStorage>;
|
|
55
|
-
useEvent: <TType extends keyof InferIOOutput<TIO
|
|
54
|
+
useEvent: <TType extends keyof InferIOOutput<MergeEvents<TEvents, TIO>>>(type: TType, callback: (data: Id<IOEventMessage<MergeEvents<TEvents, TIO>, TType>>) => void) => void;
|
|
56
55
|
useMyPresence: <T extends unknown = TPresence>(selector?: (myPresence: TPresence) => T, options?: SubscriptionHookOptions<Id<T> | null>) => [myPresence: Id<T>, updateMyPresence: Dispatch<UpdateMyPresenceAction<TPresence>>];
|
|
57
56
|
useMyself: <T extends unknown = UserInfo<TIO, TPresence>>(selector?: (myself: Id<UserInfo<TIO, TPresence>>) => T, options?: SubscriptionHookOptions<Id<T> | null>) => Id<T> | null;
|
|
58
57
|
useOther: <T extends unknown = UserInfo<TIO, TPresence>>(connectionId: string, selector?: (other: UserInfo<TIO, TPresence>) => T, options?: SubscriptionHookOptions<T | null>) => T | null;
|
|
@@ -63,16 +62,16 @@ interface CreateRoomBundle<TIO extends IOLike, TMetadata extends JsonObject, TPr
|
|
|
63
62
|
useTransact: () => (fn: (storage: TStorage) => void, origin?: string) => void;
|
|
64
63
|
useUndo: () => () => void;
|
|
65
64
|
}
|
|
66
|
-
type InferRoomStorage<TRoomBundle extends CreateRoomBundle<any, any, any, any>> = TRoomBundle extends CreateRoomBundle<any, any, any, infer IStorage> ? IStorage : never;
|
|
65
|
+
type InferRoomStorage<TRoomBundle extends CreateRoomBundle<any, any, any, any, any>> = TRoomBundle extends CreateRoomBundle<any, any, any, infer IStorage> ? IStorage : never;
|
|
67
66
|
|
|
68
67
|
interface PluvProviderProps {
|
|
69
68
|
children?: ReactNode;
|
|
70
69
|
}
|
|
71
|
-
interface CreateBundle<TIO extends IOLike, TMetadata extends JsonObject> {
|
|
72
|
-
createRoomBundle: <
|
|
70
|
+
interface CreateBundle<TIO extends IOLike, TMetadata extends JsonObject, TPresence extends JsonObject = {}, TStorage extends Record<string, CrdtType<any, any>> = {}> {
|
|
71
|
+
createRoomBundle: <TEvents extends PluvRouterEventConfig<TIO, TPresence, TStorage> = {}>(options: CreateRoomBundleOptions<TIO, TMetadata, TPresence, TStorage, TEvents>) => CreateRoomBundle<TIO, TMetadata, TPresence, TStorage, TEvents>;
|
|
73
72
|
PluvProvider: FC<PluvProviderProps>;
|
|
74
|
-
useClient: () => PluvClient<TIO, TMetadata>;
|
|
73
|
+
useClient: () => PluvClient<TIO, TPresence, TStorage, TMetadata>;
|
|
75
74
|
}
|
|
76
|
-
declare const createBundle: <TIO extends IOLike, TMetadata extends JsonObject>(client: PluvClient<TIO, TMetadata>) => CreateBundle<TIO, TMetadata>;
|
|
75
|
+
declare const createBundle: <TIO extends IOLike, TMetadata extends JsonObject = {}, TPresence extends JsonObject = {}, TStorage extends Record<string, CrdtType<any, any>> = {}>(client: PluvClient<TIO, TPresence, TStorage, TMetadata>) => CreateBundle<TIO, TMetadata, TPresence, TStorage>;
|
|
77
76
|
|
|
78
77
|
export { type CreateBundle, type CreateRoomBundle, type CreateRoomBundleOptions, type InferRoomStorage, type PluvProviderProps, type PluvRoomProviderProps, type SubscriptionHookOptions, createBundle };
|
package/dist/index.js
CHANGED
|
@@ -42,7 +42,6 @@ var import_react5 = require("react");
|
|
|
42
42
|
|
|
43
43
|
// src/createRoomBundle.tsx
|
|
44
44
|
var import_client = require("@pluv/client");
|
|
45
|
-
var import_crdt = require("@pluv/crdt");
|
|
46
45
|
var import_fast_deep_equal = __toESM(require("fast-deep-equal"));
|
|
47
46
|
var import_react4 = require("react");
|
|
48
47
|
|
|
@@ -112,18 +111,16 @@ var useSyncExternalStoreWithSelector = (subscribe, getClientSnapshot, getServerS
|
|
|
112
111
|
// src/createRoomBundle.tsx
|
|
113
112
|
var import_jsx_runtime = require("react/jsx-runtime");
|
|
114
113
|
var createRoomBundle = (client, options) => {
|
|
115
|
-
var _a;
|
|
116
|
-
const _initialStorage = (_a = options.initialStorage) != null ? _a : import_crdt.noop.doc();
|
|
117
114
|
const PluvRoomContext = (0, import_react4.createContext)(null);
|
|
118
115
|
const MockedRoomContext = (0, import_react4.createContext)({ room: null });
|
|
119
116
|
const MockedRoomProvider = (0, import_react4.memo)((props) => {
|
|
120
117
|
const { children, events, initialPresence, initialStorage, room: _room } = props;
|
|
121
118
|
const [room] = (0, import_react4.useState)(() => {
|
|
119
|
+
var _a;
|
|
122
120
|
return new import_client.MockedRoom(_room, {
|
|
123
121
|
events,
|
|
124
122
|
initialPresence,
|
|
125
|
-
initialStorage: typeof initialStorage === "function" ?
|
|
126
|
-
presence: options.presence
|
|
123
|
+
initialStorage: typeof initialStorage === "function" ? (_a = client._defs.initialStorage) == null ? void 0 : _a.getFactory(initialStorage) : client._defs.initialStorage
|
|
127
124
|
});
|
|
128
125
|
});
|
|
129
126
|
return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(MockedRoomContext.Provider, { value: { room }, children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(PluvRoomContext.Provider, { value: room, children }) });
|
|
@@ -134,14 +131,15 @@ var createRoomBundle = (client, options) => {
|
|
|
134
131
|
const rerender = useRerender();
|
|
135
132
|
const { room: mockedRoom } = (0, import_react4.useContext)(MockedRoomContext);
|
|
136
133
|
const [room] = (0, import_react4.useState)(() => {
|
|
134
|
+
var _a;
|
|
137
135
|
return client.createRoom(_room, {
|
|
138
136
|
addons: options.addons,
|
|
139
137
|
debug,
|
|
140
138
|
initialPresence,
|
|
141
|
-
initialStorage: typeof initialStorage === "function" ?
|
|
139
|
+
initialStorage: typeof initialStorage === "function" ? (_a = client._defs.initialStorage) == null ? void 0 : _a.getFactory(initialStorage) : client._defs.initialStorage,
|
|
142
140
|
metadata,
|
|
143
|
-
|
|
144
|
-
|
|
141
|
+
onAuthorizationFail,
|
|
142
|
+
router: options.router
|
|
145
143
|
});
|
|
146
144
|
});
|
|
147
145
|
(0, import_react4.useEffect)(() => {
|
|
@@ -195,7 +193,7 @@ var createRoomBundle = (client, options) => {
|
|
|
195
193
|
return canUndo;
|
|
196
194
|
};
|
|
197
195
|
const useConnection = (selector = identity, options2) => {
|
|
198
|
-
var
|
|
196
|
+
var _a;
|
|
199
197
|
const room = useRoom();
|
|
200
198
|
const subscribe = (0, import_react4.useCallback)(
|
|
201
199
|
(onStoreChange) => {
|
|
@@ -210,7 +208,7 @@ var createRoomBundle = (client, options) => {
|
|
|
210
208
|
getSnapshot,
|
|
211
209
|
getSnapshot,
|
|
212
210
|
_selector,
|
|
213
|
-
(
|
|
211
|
+
(_a = options2 == null ? void 0 : options2.isEqual) != null ? _a : import_fast_deep_equal.default
|
|
214
212
|
);
|
|
215
213
|
};
|
|
216
214
|
const useDoc = () => {
|
|
@@ -238,7 +236,7 @@ var createRoomBundle = (client, options) => {
|
|
|
238
236
|
}
|
|
239
237
|
);
|
|
240
238
|
const useMyPresence = (selector = identity, options2) => {
|
|
241
|
-
var
|
|
239
|
+
var _a;
|
|
242
240
|
const room = useRoom();
|
|
243
241
|
const subscribe = (0, import_react4.useCallback)(
|
|
244
242
|
(onStoreChange) => {
|
|
@@ -253,12 +251,12 @@ var createRoomBundle = (client, options) => {
|
|
|
253
251
|
getSnapshot,
|
|
254
252
|
getSnapshot,
|
|
255
253
|
_selector,
|
|
256
|
-
(
|
|
254
|
+
(_a = options2 == null ? void 0 : options2.isEqual) != null ? _a : import_fast_deep_equal.default
|
|
257
255
|
);
|
|
258
256
|
return [myPresence, room.updateMyPresence];
|
|
259
257
|
};
|
|
260
258
|
const useMyself = (selector = identity, options2) => {
|
|
261
|
-
var
|
|
259
|
+
var _a;
|
|
262
260
|
const room = useRoom();
|
|
263
261
|
const subscribe = (0, import_react4.useCallback)(
|
|
264
262
|
(onStoreChange) => {
|
|
@@ -278,11 +276,11 @@ var createRoomBundle = (client, options) => {
|
|
|
278
276
|
getSnapshot,
|
|
279
277
|
getSnapshot,
|
|
280
278
|
_selector,
|
|
281
|
-
(
|
|
279
|
+
(_a = options2 == null ? void 0 : options2.isEqual) != null ? _a : import_fast_deep_equal.default
|
|
282
280
|
);
|
|
283
281
|
};
|
|
284
282
|
const useOther = (connectionId, selector = identity, options2) => {
|
|
285
|
-
var
|
|
283
|
+
var _a;
|
|
286
284
|
const room = useRoom();
|
|
287
285
|
const subscribe = (0, import_react4.useCallback)(
|
|
288
286
|
(onStoreChange) => {
|
|
@@ -302,11 +300,11 @@ var createRoomBundle = (client, options) => {
|
|
|
302
300
|
getSnapshot,
|
|
303
301
|
getSnapshot,
|
|
304
302
|
_selector,
|
|
305
|
-
(
|
|
303
|
+
(_a = options2 == null ? void 0 : options2.isEqual) != null ? _a : import_fast_deep_equal.default
|
|
306
304
|
);
|
|
307
305
|
};
|
|
308
306
|
const useOthers = (selector = identity, options2) => {
|
|
309
|
-
var
|
|
307
|
+
var _a;
|
|
310
308
|
const room = useRoom();
|
|
311
309
|
const subscribe = (0, import_react4.useCallback)(
|
|
312
310
|
(onStoreChange) => {
|
|
@@ -320,7 +318,7 @@ var createRoomBundle = (client, options) => {
|
|
|
320
318
|
getSnapshot,
|
|
321
319
|
getSnapshot,
|
|
322
320
|
selector,
|
|
323
|
-
(
|
|
321
|
+
(_a = options2 == null ? void 0 : options2.isEqual) != null ? _a : (a, b) => {
|
|
324
322
|
if (Array.isArray(a) && Array.isArray(b) && a.length === b.length) {
|
|
325
323
|
return shallowArrayEqual(a, b);
|
|
326
324
|
}
|
|
@@ -333,7 +331,7 @@ var createRoomBundle = (client, options) => {
|
|
|
333
331
|
return room.redo;
|
|
334
332
|
};
|
|
335
333
|
const useStorage = (key, selector = identity, options2) => {
|
|
336
|
-
var
|
|
334
|
+
var _a, _b;
|
|
337
335
|
const room = useRoom();
|
|
338
336
|
const rerender = useRerender();
|
|
339
337
|
room.subscribe("storage-loaded", () => {
|
|
@@ -354,7 +352,7 @@ var createRoomBundle = (client, options) => {
|
|
|
354
352
|
getSnapshot,
|
|
355
353
|
getSnapshot,
|
|
356
354
|
_selector,
|
|
357
|
-
(
|
|
355
|
+
(_a = options2 == null ? void 0 : options2.isEqual) != null ? _a : import_fast_deep_equal.default
|
|
358
356
|
);
|
|
359
357
|
const sharedType = (_b = room.getStorage(key)) != null ? _b : null;
|
|
360
358
|
return [data, sharedType];
|
package/dist/index.mjs
CHANGED
|
@@ -6,7 +6,6 @@ import { createContext as createContext2, memo as memo2, useContext as useContex
|
|
|
6
6
|
|
|
7
7
|
// src/createRoomBundle.tsx
|
|
8
8
|
import { MockedRoom } from "@pluv/client";
|
|
9
|
-
import { noop } from "@pluv/crdt";
|
|
10
9
|
import fastDeepEqual from "fast-deep-equal";
|
|
11
10
|
import { createContext, memo, useCallback as useCallback3, useContext, useEffect as useEffect2, useMemo, useState as useState3 } from "react";
|
|
12
11
|
|
|
@@ -76,18 +75,16 @@ var useSyncExternalStoreWithSelector = (subscribe, getClientSnapshot, getServerS
|
|
|
76
75
|
// src/createRoomBundle.tsx
|
|
77
76
|
import { jsx } from "react/jsx-runtime";
|
|
78
77
|
var createRoomBundle = (client, options) => {
|
|
79
|
-
var _a;
|
|
80
|
-
const _initialStorage = (_a = options.initialStorage) != null ? _a : noop.doc();
|
|
81
78
|
const PluvRoomContext = createContext(null);
|
|
82
79
|
const MockedRoomContext = createContext({ room: null });
|
|
83
80
|
const MockedRoomProvider = memo((props) => {
|
|
84
81
|
const { children, events, initialPresence, initialStorage, room: _room } = props;
|
|
85
82
|
const [room] = useState3(() => {
|
|
83
|
+
var _a;
|
|
86
84
|
return new MockedRoom(_room, {
|
|
87
85
|
events,
|
|
88
86
|
initialPresence,
|
|
89
|
-
initialStorage: typeof initialStorage === "function" ?
|
|
90
|
-
presence: options.presence
|
|
87
|
+
initialStorage: typeof initialStorage === "function" ? (_a = client._defs.initialStorage) == null ? void 0 : _a.getFactory(initialStorage) : client._defs.initialStorage
|
|
91
88
|
});
|
|
92
89
|
});
|
|
93
90
|
return /* @__PURE__ */ jsx(MockedRoomContext.Provider, { value: { room }, children: /* @__PURE__ */ jsx(PluvRoomContext.Provider, { value: room, children }) });
|
|
@@ -98,14 +95,15 @@ var createRoomBundle = (client, options) => {
|
|
|
98
95
|
const rerender = useRerender();
|
|
99
96
|
const { room: mockedRoom } = useContext(MockedRoomContext);
|
|
100
97
|
const [room] = useState3(() => {
|
|
98
|
+
var _a;
|
|
101
99
|
return client.createRoom(_room, {
|
|
102
100
|
addons: options.addons,
|
|
103
101
|
debug,
|
|
104
102
|
initialPresence,
|
|
105
|
-
initialStorage: typeof initialStorage === "function" ?
|
|
103
|
+
initialStorage: typeof initialStorage === "function" ? (_a = client._defs.initialStorage) == null ? void 0 : _a.getFactory(initialStorage) : client._defs.initialStorage,
|
|
106
104
|
metadata,
|
|
107
|
-
|
|
108
|
-
|
|
105
|
+
onAuthorizationFail,
|
|
106
|
+
router: options.router
|
|
109
107
|
});
|
|
110
108
|
});
|
|
111
109
|
useEffect2(() => {
|
|
@@ -159,7 +157,7 @@ var createRoomBundle = (client, options) => {
|
|
|
159
157
|
return canUndo;
|
|
160
158
|
};
|
|
161
159
|
const useConnection = (selector = identity, options2) => {
|
|
162
|
-
var
|
|
160
|
+
var _a;
|
|
163
161
|
const room = useRoom();
|
|
164
162
|
const subscribe = useCallback3(
|
|
165
163
|
(onStoreChange) => {
|
|
@@ -174,7 +172,7 @@ var createRoomBundle = (client, options) => {
|
|
|
174
172
|
getSnapshot,
|
|
175
173
|
getSnapshot,
|
|
176
174
|
_selector,
|
|
177
|
-
(
|
|
175
|
+
(_a = options2 == null ? void 0 : options2.isEqual) != null ? _a : fastDeepEqual
|
|
178
176
|
);
|
|
179
177
|
};
|
|
180
178
|
const useDoc = () => {
|
|
@@ -202,7 +200,7 @@ var createRoomBundle = (client, options) => {
|
|
|
202
200
|
}
|
|
203
201
|
);
|
|
204
202
|
const useMyPresence = (selector = identity, options2) => {
|
|
205
|
-
var
|
|
203
|
+
var _a;
|
|
206
204
|
const room = useRoom();
|
|
207
205
|
const subscribe = useCallback3(
|
|
208
206
|
(onStoreChange) => {
|
|
@@ -217,12 +215,12 @@ var createRoomBundle = (client, options) => {
|
|
|
217
215
|
getSnapshot,
|
|
218
216
|
getSnapshot,
|
|
219
217
|
_selector,
|
|
220
|
-
(
|
|
218
|
+
(_a = options2 == null ? void 0 : options2.isEqual) != null ? _a : fastDeepEqual
|
|
221
219
|
);
|
|
222
220
|
return [myPresence, room.updateMyPresence];
|
|
223
221
|
};
|
|
224
222
|
const useMyself = (selector = identity, options2) => {
|
|
225
|
-
var
|
|
223
|
+
var _a;
|
|
226
224
|
const room = useRoom();
|
|
227
225
|
const subscribe = useCallback3(
|
|
228
226
|
(onStoreChange) => {
|
|
@@ -242,11 +240,11 @@ var createRoomBundle = (client, options) => {
|
|
|
242
240
|
getSnapshot,
|
|
243
241
|
getSnapshot,
|
|
244
242
|
_selector,
|
|
245
|
-
(
|
|
243
|
+
(_a = options2 == null ? void 0 : options2.isEqual) != null ? _a : fastDeepEqual
|
|
246
244
|
);
|
|
247
245
|
};
|
|
248
246
|
const useOther = (connectionId, selector = identity, options2) => {
|
|
249
|
-
var
|
|
247
|
+
var _a;
|
|
250
248
|
const room = useRoom();
|
|
251
249
|
const subscribe = useCallback3(
|
|
252
250
|
(onStoreChange) => {
|
|
@@ -266,11 +264,11 @@ var createRoomBundle = (client, options) => {
|
|
|
266
264
|
getSnapshot,
|
|
267
265
|
getSnapshot,
|
|
268
266
|
_selector,
|
|
269
|
-
(
|
|
267
|
+
(_a = options2 == null ? void 0 : options2.isEqual) != null ? _a : fastDeepEqual
|
|
270
268
|
);
|
|
271
269
|
};
|
|
272
270
|
const useOthers = (selector = identity, options2) => {
|
|
273
|
-
var
|
|
271
|
+
var _a;
|
|
274
272
|
const room = useRoom();
|
|
275
273
|
const subscribe = useCallback3(
|
|
276
274
|
(onStoreChange) => {
|
|
@@ -284,7 +282,7 @@ var createRoomBundle = (client, options) => {
|
|
|
284
282
|
getSnapshot,
|
|
285
283
|
getSnapshot,
|
|
286
284
|
selector,
|
|
287
|
-
(
|
|
285
|
+
(_a = options2 == null ? void 0 : options2.isEqual) != null ? _a : (a, b) => {
|
|
288
286
|
if (Array.isArray(a) && Array.isArray(b) && a.length === b.length) {
|
|
289
287
|
return shallowArrayEqual(a, b);
|
|
290
288
|
}
|
|
@@ -297,7 +295,7 @@ var createRoomBundle = (client, options) => {
|
|
|
297
295
|
return room.redo;
|
|
298
296
|
};
|
|
299
297
|
const useStorage = (key, selector = identity, options2) => {
|
|
300
|
-
var
|
|
298
|
+
var _a, _b;
|
|
301
299
|
const room = useRoom();
|
|
302
300
|
const rerender = useRerender();
|
|
303
301
|
room.subscribe("storage-loaded", () => {
|
|
@@ -318,7 +316,7 @@ var createRoomBundle = (client, options) => {
|
|
|
318
316
|
getSnapshot,
|
|
319
317
|
getSnapshot,
|
|
320
318
|
_selector,
|
|
321
|
-
(
|
|
319
|
+
(_a = options2 == null ? void 0 : options2.isEqual) != null ? _a : fastDeepEqual
|
|
322
320
|
);
|
|
323
321
|
const sharedType = (_b = room.getStorage(key)) != null ? _b : null;
|
|
324
322
|
return [data, sharedType];
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@pluv/react",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.28.0",
|
|
4
4
|
"description": "@pluv/client React.js bindings",
|
|
5
5
|
"author": "leedavidcs",
|
|
6
6
|
"license": "MIT",
|
|
@@ -18,22 +18,22 @@
|
|
|
18
18
|
},
|
|
19
19
|
"dependencies": {
|
|
20
20
|
"fast-deep-equal": "^3.1.3",
|
|
21
|
-
"@pluv/client": "^0.
|
|
22
|
-
"@pluv/crdt": "^0.
|
|
23
|
-
"@pluv/types": "^0.
|
|
21
|
+
"@pluv/client": "^0.28.0",
|
|
22
|
+
"@pluv/crdt": "^0.28.0",
|
|
23
|
+
"@pluv/types": "^0.28.0"
|
|
24
24
|
},
|
|
25
25
|
"peerDependencies": {
|
|
26
26
|
"@types/react": "^18.0.0",
|
|
27
27
|
"react": "^18.0.0"
|
|
28
28
|
},
|
|
29
29
|
"devDependencies": {
|
|
30
|
-
"@types/react": "^18.3.
|
|
30
|
+
"@types/react": "^18.3.6",
|
|
31
31
|
"eslint": "^8.57.0",
|
|
32
32
|
"react": "^18.3.1",
|
|
33
|
-
"tsup": "^8.
|
|
34
|
-
"typescript": "^5.
|
|
35
|
-
"@pluv/tsconfig": "^0.
|
|
36
|
-
"eslint-config-pluv": "^0.
|
|
33
|
+
"tsup": "^8.3.0",
|
|
34
|
+
"typescript": "^5.6.2",
|
|
35
|
+
"@pluv/tsconfig": "^0.28.0",
|
|
36
|
+
"eslint-config-pluv": "^0.28.0"
|
|
37
37
|
},
|
|
38
38
|
"scripts": {
|
|
39
39
|
"build": "tsup src/index.ts --format esm,cjs --dts --external react",
|
package/src/createBundle.tsx
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type { PluvClient } from "@pluv/client";
|
|
1
|
+
import type { PluvClient, PluvRouterEventConfig } from "@pluv/client";
|
|
2
2
|
import type { CrdtType } from "@pluv/crdt";
|
|
3
3
|
import type { IOLike, JsonObject } from "@pluv/types";
|
|
4
4
|
import type { FC, ReactNode } from "react";
|
|
@@ -10,22 +10,32 @@ export interface PluvProviderProps {
|
|
|
10
10
|
children?: ReactNode;
|
|
11
11
|
}
|
|
12
12
|
|
|
13
|
-
export interface CreateBundle<
|
|
13
|
+
export interface CreateBundle<
|
|
14
|
+
TIO extends IOLike,
|
|
15
|
+
TMetadata extends JsonObject,
|
|
16
|
+
TPresence extends JsonObject = {},
|
|
17
|
+
TStorage extends Record<string, CrdtType<any, any>> = {},
|
|
18
|
+
> {
|
|
14
19
|
// factories
|
|
15
|
-
createRoomBundle: <
|
|
16
|
-
options: CreateRoomBundleOptions<TIO, TMetadata, TPresence, TStorage>,
|
|
17
|
-
) => CreateRoomBundle<TIO, TMetadata, TPresence, TStorage>;
|
|
20
|
+
createRoomBundle: <TEvents extends PluvRouterEventConfig<TIO, TPresence, TStorage> = {}>(
|
|
21
|
+
options: CreateRoomBundleOptions<TIO, TMetadata, TPresence, TStorage, TEvents>,
|
|
22
|
+
) => CreateRoomBundle<TIO, TMetadata, TPresence, TStorage, TEvents>;
|
|
18
23
|
|
|
19
24
|
// components
|
|
20
25
|
PluvProvider: FC<PluvProviderProps>;
|
|
21
26
|
|
|
22
27
|
// hooks
|
|
23
|
-
useClient: () => PluvClient<TIO, TMetadata>;
|
|
28
|
+
useClient: () => PluvClient<TIO, TPresence, TStorage, TMetadata>;
|
|
24
29
|
}
|
|
25
30
|
|
|
26
|
-
export const createBundle = <
|
|
27
|
-
|
|
28
|
-
|
|
31
|
+
export const createBundle = <
|
|
32
|
+
TIO extends IOLike,
|
|
33
|
+
TMetadata extends JsonObject = {},
|
|
34
|
+
TPresence extends JsonObject = {},
|
|
35
|
+
TStorage extends Record<string, CrdtType<any, any>> = {},
|
|
36
|
+
>(
|
|
37
|
+
client: PluvClient<TIO, TPresence, TStorage, TMetadata>,
|
|
38
|
+
): CreateBundle<TIO, TMetadata, TPresence, TStorage> => {
|
|
29
39
|
/**
|
|
30
40
|
* !HACK
|
|
31
41
|
* @description We'll let the context error out if client is not provided,
|
|
@@ -33,7 +43,7 @@ export const createBundle = <TIO extends IOLike, TMetadata extends JsonObject>(
|
|
|
33
43
|
* @author leedavidcs
|
|
34
44
|
* @date October 27, 2022
|
|
35
45
|
*/
|
|
36
|
-
const PluvContext = createContext<PluvClient<TIO, TMetadata>>(null as any);
|
|
46
|
+
const PluvContext = createContext<PluvClient<TIO, TPresence, TStorage, TMetadata>>(null as any);
|
|
37
47
|
|
|
38
48
|
const PluvProvider = memo<PluvProviderProps>((props) => {
|
|
39
49
|
const { children } = props;
|
|
@@ -43,14 +53,11 @@ export const createBundle = <TIO extends IOLike, TMetadata extends JsonObject>(
|
|
|
43
53
|
|
|
44
54
|
PluvProvider.displayName = "PluvProvider";
|
|
45
55
|
|
|
46
|
-
const useClient = (): PluvClient<TIO, TMetadata> => useContext(PluvContext);
|
|
56
|
+
const useClient = (): PluvClient<TIO, TPresence, TStorage, TMetadata> => useContext(PluvContext);
|
|
47
57
|
|
|
48
|
-
const createRoomBundle = <
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
>(
|
|
52
|
-
options: CreateRoomBundleOptions<TIO, TMetadata, TPresence, TStorage>,
|
|
53
|
-
): CreateRoomBundle<TIO, TMetadata, TPresence, TStorage> => _createRoomBundle(client, options);
|
|
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);
|
|
54
61
|
|
|
55
62
|
return {
|
|
56
63
|
createRoomBundle,
|
package/src/createRoomBundle.tsx
CHANGED
|
@@ -1,18 +1,20 @@
|
|
|
1
1
|
import type {
|
|
2
2
|
AbstractRoom,
|
|
3
|
+
CreateRoomOptions,
|
|
4
|
+
MergeEvents,
|
|
3
5
|
MockedRoomEvents,
|
|
4
6
|
PluvClient,
|
|
5
7
|
PluvRoom,
|
|
6
8
|
PluvRoomAddon,
|
|
7
9
|
PluvRoomDebug,
|
|
8
|
-
|
|
10
|
+
PluvRouter,
|
|
11
|
+
PluvRouterEventConfig,
|
|
9
12
|
UserInfo,
|
|
10
13
|
WebSocketConnection,
|
|
11
14
|
} from "@pluv/client";
|
|
12
15
|
import { MockedRoom } from "@pluv/client";
|
|
13
|
-
import type { AbstractCrdtDoc,
|
|
14
|
-
import {
|
|
15
|
-
import type { IOEventMessage, IOLike, Id, InferIOInput, InferIOOutput, InputZodLike, JsonObject } from "@pluv/types";
|
|
16
|
+
import type { AbstractCrdtDoc, CrdtType, InferCrdtJson } from "@pluv/crdt";
|
|
17
|
+
import type { IOEventMessage, IOLike, Id, InferIOInput, InferIOOutput, JsonObject } from "@pluv/types";
|
|
16
18
|
import fastDeepEqual from "fast-deep-equal";
|
|
17
19
|
import type { Dispatch, FC, ReactNode } from "react";
|
|
18
20
|
import { createContext, memo, useCallback, useContext, useEffect, useMemo, useState } from "react";
|
|
@@ -23,10 +25,10 @@ export type CreateRoomBundleOptions<
|
|
|
23
25
|
TMetadata extends JsonObject = {},
|
|
24
26
|
TPresence extends JsonObject = {},
|
|
25
27
|
TStorage extends Record<string, CrdtType<any, any>> = {},
|
|
28
|
+
TEvents extends PluvRouterEventConfig<TIO, TPresence, TStorage> = {},
|
|
26
29
|
> = {
|
|
27
30
|
addons?: readonly PluvRoomAddon<TIO, TMetadata, TPresence, TStorage>[];
|
|
28
|
-
|
|
29
|
-
presence?: InputZodLike<TPresence>;
|
|
31
|
+
router?: PluvRouter<TIO, TPresence, TStorage, TEvents>;
|
|
30
32
|
};
|
|
31
33
|
|
|
32
34
|
type BaseRoomProviderProps<TPresence extends JsonObject, TStorage extends Record<string, CrdtType<any, any>>> = {
|
|
@@ -39,8 +41,9 @@ export type MockedRoomProviderProps<
|
|
|
39
41
|
TIO extends IOLike,
|
|
40
42
|
TPresence extends JsonObject,
|
|
41
43
|
TStorage extends Record<string, CrdtType<any, any>>,
|
|
44
|
+
TEvents extends PluvRouterEventConfig<TIO, TPresence, TStorage> = {},
|
|
42
45
|
> = BaseRoomProviderProps<TPresence, TStorage> & {
|
|
43
|
-
events?: MockedRoomEvents<TIO
|
|
46
|
+
events?: MockedRoomEvents<MergeEvents<TEvents, TIO>>;
|
|
44
47
|
};
|
|
45
48
|
|
|
46
49
|
export type PluvRoomProviderProps<
|
|
@@ -79,16 +82,17 @@ export interface CreateRoomBundle<
|
|
|
79
82
|
TMetadata extends JsonObject,
|
|
80
83
|
TPresence extends JsonObject,
|
|
81
84
|
TStorage extends Record<string, CrdtType<any, any>>,
|
|
85
|
+
TEvents extends PluvRouterEventConfig<TIO, TPresence, TStorage> = {},
|
|
82
86
|
> {
|
|
83
87
|
// components
|
|
84
88
|
MockedRoomProvider: FC<MockedRoomProviderProps<TIO, TPresence, TStorage>>;
|
|
85
89
|
PluvRoomProvider: FC<PluvRoomProviderProps<TIO, TMetadata, TPresence, TStorage>>;
|
|
86
90
|
|
|
87
91
|
// proxies
|
|
88
|
-
event: EventProxy<TIO
|
|
92
|
+
event: EventProxy<MergeEvents<TEvents, TIO>>;
|
|
89
93
|
|
|
90
94
|
// hooks
|
|
91
|
-
useBroadcast: () => BroadcastProxy<TIO
|
|
95
|
+
useBroadcast: () => BroadcastProxy<MergeEvents<TEvents, TIO>>;
|
|
92
96
|
useCanRedo: () => boolean;
|
|
93
97
|
useCanUndo: () => boolean;
|
|
94
98
|
useConnection: <T extends unknown = WebSocketConnection>(
|
|
@@ -96,9 +100,9 @@ export interface CreateRoomBundle<
|
|
|
96
100
|
options?: SubscriptionHookOptions<Id<T>>,
|
|
97
101
|
) => Id<T>;
|
|
98
102
|
useDoc: () => AbstractCrdtDoc<TStorage>;
|
|
99
|
-
useEvent: <TType extends keyof InferIOOutput<TIO
|
|
103
|
+
useEvent: <TType extends keyof InferIOOutput<MergeEvents<TEvents, TIO>>>(
|
|
100
104
|
type: TType,
|
|
101
|
-
callback: (data: Id<IOEventMessage<
|
|
105
|
+
callback: (data: Id<IOEventMessage<MergeEvents<TEvents, TIO>, TType>>) => void,
|
|
102
106
|
) => void;
|
|
103
107
|
useMyPresence: <T extends unknown = TPresence>(
|
|
104
108
|
selector?: (myPresence: TPresence) => T,
|
|
@@ -128,7 +132,7 @@ export interface CreateRoomBundle<
|
|
|
128
132
|
useUndo: () => () => void;
|
|
129
133
|
}
|
|
130
134
|
|
|
131
|
-
export type InferRoomStorage<TRoomBundle extends CreateRoomBundle<any, any, any, any>> =
|
|
135
|
+
export type InferRoomStorage<TRoomBundle extends CreateRoomBundle<any, any, any, any, any>> =
|
|
132
136
|
TRoomBundle extends CreateRoomBundle<any, any, any, infer IStorage> ? IStorage : never;
|
|
133
137
|
|
|
134
138
|
export const createRoomBundle = <
|
|
@@ -136,12 +140,11 @@ export const createRoomBundle = <
|
|
|
136
140
|
TMetadata extends JsonObject = {},
|
|
137
141
|
TPresence extends JsonObject = {},
|
|
138
142
|
TStorage extends Record<string, CrdtType<any, any>> = {},
|
|
143
|
+
TEvents extends PluvRouterEventConfig<TIO, TPresence, TStorage> = {},
|
|
139
144
|
>(
|
|
140
|
-
client: PluvClient<TIO, TMetadata>,
|
|
141
|
-
options: CreateRoomBundleOptions<TIO, TMetadata, TPresence, TStorage>,
|
|
142
|
-
): CreateRoomBundle<TIO, TMetadata, TPresence, TStorage> => {
|
|
143
|
-
const _initialStorage = (options.initialStorage ?? noop.doc()) as AbstractCrdtDocFactory<TStorage>;
|
|
144
|
-
|
|
145
|
+
client: PluvClient<TIO, TPresence, TStorage, TMetadata>,
|
|
146
|
+
options: CreateRoomBundleOptions<TIO, TMetadata, TPresence, TStorage, TEvents>,
|
|
147
|
+
): CreateRoomBundle<TIO, TMetadata, TPresence, TStorage, TEvents> => {
|
|
145
148
|
/**
|
|
146
149
|
* !HACK
|
|
147
150
|
* @description We'll let the context error out if the room is not provided,
|
|
@@ -158,13 +161,14 @@ export const createRoomBundle = <
|
|
|
158
161
|
const MockedRoomProvider = memo<MockedRoomProviderProps<TIO, TPresence, TStorage>>((props) => {
|
|
159
162
|
const { children, events, initialPresence, initialStorage, room: _room } = props;
|
|
160
163
|
|
|
161
|
-
const [room] = useState<MockedRoom<TIO, TPresence, TStorage>>(() => {
|
|
162
|
-
return new MockedRoom<TIO, TPresence, TStorage>(_room, {
|
|
164
|
+
const [room] = useState<MockedRoom<TIO, TPresence, TStorage, TEvents>>(() => {
|
|
165
|
+
return new MockedRoom<TIO, TPresence, TStorage, TEvents>(_room, {
|
|
163
166
|
events,
|
|
164
167
|
initialPresence,
|
|
165
168
|
initialStorage:
|
|
166
|
-
typeof initialStorage === "function"
|
|
167
|
-
|
|
169
|
+
typeof initialStorage === "function"
|
|
170
|
+
? client._defs.initialStorage?.getFactory(initialStorage)
|
|
171
|
+
: client._defs.initialStorage,
|
|
168
172
|
});
|
|
169
173
|
});
|
|
170
174
|
|
|
@@ -183,17 +187,19 @@ export const createRoomBundle = <
|
|
|
183
187
|
const rerender = useRerender();
|
|
184
188
|
const { room: mockedRoom } = useContext(MockedRoomContext);
|
|
185
189
|
|
|
186
|
-
const [room] = useState<PluvRoom<TIO, TMetadata, TPresence, TStorage>>(() => {
|
|
187
|
-
return client.createRoom
|
|
190
|
+
const [room] = useState<PluvRoom<TIO, TMetadata, TPresence, TStorage, TEvents>>(() => {
|
|
191
|
+
return client.createRoom(_room, {
|
|
188
192
|
addons: options.addons,
|
|
189
193
|
debug,
|
|
190
194
|
initialPresence,
|
|
191
195
|
initialStorage:
|
|
192
|
-
typeof initialStorage === "function"
|
|
196
|
+
typeof initialStorage === "function"
|
|
197
|
+
? client._defs.initialStorage?.getFactory(initialStorage)
|
|
198
|
+
: client._defs.initialStorage,
|
|
193
199
|
metadata,
|
|
194
|
-
presence: options.presence,
|
|
195
200
|
onAuthorizationFail,
|
|
196
|
-
|
|
201
|
+
router: options.router,
|
|
202
|
+
} as CreateRoomOptions<TIO, TPresence, TStorage, TMetadata, TEvents>);
|
|
197
203
|
});
|
|
198
204
|
|
|
199
205
|
useEffect(() => {
|
|
@@ -221,24 +227,31 @@ export const createRoomBundle = <
|
|
|
221
227
|
|
|
222
228
|
const useRoom = () => useContext(PluvRoomContext);
|
|
223
229
|
|
|
224
|
-
const useBroadcast = (): BroadcastProxy<TIO
|
|
230
|
+
const useBroadcast = (): BroadcastProxy<MergeEvents<TEvents, TIO>> => {
|
|
225
231
|
const room = useRoom();
|
|
226
232
|
|
|
227
233
|
const broadcast = useCallback(
|
|
228
|
-
<TEvent extends keyof InferIOInput<
|
|
234
|
+
<TEvent extends keyof InferIOInput<MergeEvents<TEvents, TIO>>>(
|
|
235
|
+
event: TEvent,
|
|
236
|
+
data: Id<InferIOInput<MergeEvents<TEvents, TIO>>[TEvent]>,
|
|
237
|
+
) => {
|
|
229
238
|
room.broadcast(event, data);
|
|
230
239
|
},
|
|
231
240
|
[room],
|
|
232
241
|
);
|
|
233
242
|
|
|
234
|
-
return useMemo((): BroadcastProxy<TIO
|
|
243
|
+
return useMemo((): BroadcastProxy<MergeEvents<TEvents, TIO>> => {
|
|
235
244
|
return new Proxy(broadcast, {
|
|
236
245
|
get(fn, prop) {
|
|
237
|
-
return (
|
|
238
|
-
|
|
246
|
+
return (
|
|
247
|
+
data: Id<
|
|
248
|
+
InferIOInput<MergeEvents<TEvents, TIO>>[keyof InferIOInput<MergeEvents<TEvents, TIO>>]
|
|
249
|
+
>,
|
|
250
|
+
): void => {
|
|
251
|
+
return fn(prop as keyof InferIOInput<MergeEvents<TEvents, TIO>>, data);
|
|
239
252
|
};
|
|
240
253
|
},
|
|
241
|
-
}) as BroadcastProxy<TIO
|
|
254
|
+
}) as BroadcastProxy<MergeEvents<TEvents, TIO>>;
|
|
242
255
|
}, [broadcast]);
|
|
243
256
|
};
|
|
244
257
|
|
|
@@ -298,9 +311,9 @@ export const createRoomBundle = <
|
|
|
298
311
|
return room.getDoc();
|
|
299
312
|
};
|
|
300
313
|
|
|
301
|
-
const useEvent = <TType extends keyof InferIOOutput<TIO
|
|
314
|
+
const useEvent = <TType extends keyof InferIOOutput<MergeEvents<TEvents, TIO>>>(
|
|
302
315
|
type: TType,
|
|
303
|
-
callback: (data: Id<IOEventMessage<
|
|
316
|
+
callback: (data: Id<IOEventMessage<MergeEvents<TEvents, TIO>, TType>>) => void,
|
|
304
317
|
): void => {
|
|
305
318
|
const room = useRoom();
|
|
306
319
|
|
|
@@ -318,15 +331,19 @@ export const createRoomBundle = <
|
|
|
318
331
|
{
|
|
319
332
|
get(_, prop) {
|
|
320
333
|
const useProxyEvent = (
|
|
321
|
-
callback: (
|
|
334
|
+
callback: (
|
|
335
|
+
data: Id<
|
|
336
|
+
IOEventMessage<MergeEvents<TEvents, TIO>, keyof InferIOOutput<MergeEvents<TEvents, TIO>>>
|
|
337
|
+
>,
|
|
338
|
+
) => void,
|
|
322
339
|
): void => {
|
|
323
|
-
return useEvent(prop as keyof InferIOOutput<TIO
|
|
340
|
+
return useEvent(prop as keyof InferIOOutput<MergeEvents<TEvents, TIO>>, callback);
|
|
324
341
|
};
|
|
325
342
|
|
|
326
343
|
return { useEvent: useProxyEvent };
|
|
327
344
|
},
|
|
328
345
|
},
|
|
329
|
-
) as EventProxy<TIO
|
|
346
|
+
) as EventProxy<MergeEvents<TEvents, TIO>>;
|
|
330
347
|
|
|
331
348
|
const useMyPresence = <T extends unknown = TPresence>(
|
|
332
349
|
selector = identity as (myPresence: TPresence) => T,
|
|
@@ -26,7 +26,7 @@ export const useSyncExternalStoreWithSelector = <TSnapshot, TSelection>(
|
|
|
26
26
|
* @description Memoize only the last snapshot so that we can only rerender on changes
|
|
27
27
|
* @date June 22, 2024
|
|
28
28
|
*/
|
|
29
|
-
cacheRef.current = isUnchanged ? cached ?? snapshot : snapshot;
|
|
29
|
+
cacheRef.current = isUnchanged ? (cached ?? snapshot) : snapshot;
|
|
30
30
|
|
|
31
31
|
return cacheRef.current;
|
|
32
32
|
}
|
|
@@ -45,7 +45,7 @@ export const useSyncExternalStoreWithSelector = <TSnapshot, TSelection>(
|
|
|
45
45
|
* @description Memoize only the last snapshot so that we can only rerender on changes
|
|
46
46
|
* @date June 22, 2024
|
|
47
47
|
*/
|
|
48
|
-
cacheRef.current = isUnchanged ? cached ?? snapshot : snapshot;
|
|
48
|
+
cacheRef.current = isUnchanged ? (cached ?? snapshot) : snapshot;
|
|
49
49
|
|
|
50
50
|
return cacheRef.current;
|
|
51
51
|
};
|
package/src/internal/index.ts
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
export { useRerender,
|
|
1
|
+
export { useRerender, useSyncExternalStoreWithSelector } from "./hooks";
|
|
2
2
|
export { identity, shallowArrayEqual } from "./utils";
|