@pluv/react 0.25.4 → 0.27.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 +176 -0
- package/dist/index.d.mts +23 -19
- package/dist/index.d.ts +23 -19
- package/dist/index.js +5 -5
- package/dist/index.mjs +5 -5
- package/package.json +9 -9
- package/src/createBundle.tsx +24 -15
- package/src/createRoomBundle.tsx +58 -35
- 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.27.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
|
+
[32mCJS[39m [1mdist/index.js [22m[32m14.26 KB[39m
|
|
12
|
+
[32mCJS[39m ⚡️ Build success in 101ms
|
|
13
|
+
[32mESM[39m [1mdist/index.mjs [22m[32m11.85 KB[39m
|
|
14
|
+
[32mESM[39m ⚡️ Build success in 102ms
|
|
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 5825ms
|
|
17
|
+
[32mDTS[39m [1mdist/index.d.mts [22m[32m6.12 KB[39m
|
|
18
|
+
[32mDTS[39m [1mdist/index.d.ts [22m[32m6.12 KB[39m
|
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,181 @@
|
|
|
1
1
|
# @pluv/react
|
|
2
2
|
|
|
3
|
+
## 0.27.0
|
|
4
|
+
|
|
5
|
+
### Minor Changes
|
|
6
|
+
|
|
7
|
+
- 19ed36c: Updated `createClient` and `createRoomBundle` object params to better support automatic type inference.
|
|
8
|
+
|
|
9
|
+
```ts
|
|
10
|
+
// Before
|
|
11
|
+
import { createClient } from "@pluv/react";
|
|
12
|
+
import { yjs } from "@pluv/crdt-yjs";
|
|
13
|
+
import { z } from "zod";
|
|
14
|
+
import type { ioServer } from "./server/ioServer";
|
|
15
|
+
|
|
16
|
+
const client = createClient<typeof ioServer>({
|
|
17
|
+
authEndpoint: ({ room }) => "MY_AUTH_URL",
|
|
18
|
+
wsEndpoint: ({ room }) => "MY_WEBSOCKET_URL",
|
|
19
|
+
});
|
|
20
|
+
|
|
21
|
+
client.createRoom("my-example-room", {
|
|
22
|
+
presence: z.object({
|
|
23
|
+
selectionId: z.string().nullish(),
|
|
24
|
+
}),
|
|
25
|
+
initialPresence: {
|
|
26
|
+
selectionId: null,
|
|
27
|
+
},
|
|
28
|
+
initialStorage: yjs.doc(() => ({
|
|
29
|
+
messages: yjs.array<string>([]),
|
|
30
|
+
})),
|
|
31
|
+
});
|
|
32
|
+
|
|
33
|
+
// After
|
|
34
|
+
|
|
35
|
+
import { createBundle, createClient } from "@pluv/react";
|
|
36
|
+
|
|
37
|
+
const client = createClient({
|
|
38
|
+
authEndpoint: ({ room }) => "MY_AUTH_URL",
|
|
39
|
+
wsEndpoint: ({ room }) => "MY_WEBSOCKET_URL",
|
|
40
|
+
/**
|
|
41
|
+
* @description The ioServer type now needs to be inferred on this property
|
|
42
|
+
* instead of within the generic on `createClient`. This is because of
|
|
43
|
+
* limitations with TypeScript not yet supporting partial type-inference
|
|
44
|
+
* for generics. Ensure to no-loonger include any generics on `createClient`
|
|
45
|
+
*/
|
|
46
|
+
infer: (i) => ({ io: i<typeof ioServer> }),
|
|
47
|
+
// Now moved to `createClient` from `PluvClient.createRoom`
|
|
48
|
+
presence: z.object({
|
|
49
|
+
selectionId: z.string().nullish(),
|
|
50
|
+
}),
|
|
51
|
+
/**
|
|
52
|
+
* @description Now added to `createClient` to specify defaults for all
|
|
53
|
+
* rooms, and to infer types for storage. This value will be overwritten by
|
|
54
|
+
* `PluvClient.createRoom`.
|
|
55
|
+
*/
|
|
56
|
+
initialStorage: yjs.doc(() => ({
|
|
57
|
+
messages: yjs.array<string>([]),
|
|
58
|
+
})),
|
|
59
|
+
});
|
|
60
|
+
|
|
61
|
+
const { createRoomBundle } = createBundle(client);
|
|
62
|
+
const pluv = createRoomBundle({});
|
|
63
|
+
```
|
|
64
|
+
|
|
65
|
+
### Patch Changes
|
|
66
|
+
|
|
67
|
+
- 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.
|
|
68
|
+
|
|
69
|
+
```ts
|
|
70
|
+
// Backend Server
|
|
71
|
+
import { createIO } from "@pluv/io";
|
|
72
|
+
|
|
73
|
+
const io = createIO({ /* ... */ });
|
|
74
|
+
const ioServer = io.server({
|
|
75
|
+
router: io.router({
|
|
76
|
+
multiply2: io.procedure
|
|
77
|
+
.input(z.object({ value: z.number() }))
|
|
78
|
+
.broadcast(({ value }) => ({
|
|
79
|
+
multiplied2: { value: value * 2 },
|
|
80
|
+
})),
|
|
81
|
+
}),
|
|
82
|
+
});
|
|
83
|
+
|
|
84
|
+
// Frontend Client
|
|
85
|
+
import { createBundle createClient } from "@pluv/react";
|
|
86
|
+
|
|
87
|
+
const io = createClient({ /* ... */ });
|
|
88
|
+
|
|
89
|
+
const { createRoomBundle } = createBundle(io);
|
|
90
|
+
const pluv = createRoomBundle({
|
|
91
|
+
// ...
|
|
92
|
+
router: io.router({
|
|
93
|
+
add5: io.procedure
|
|
94
|
+
.input(z.object({ value: z.number() }))
|
|
95
|
+
.broadcast(({ value }) => ({
|
|
96
|
+
/**
|
|
97
|
+
* @description Because `ioServer` does not specify `added5`,
|
|
98
|
+
* this will be forwarded to connected peers.
|
|
99
|
+
*/
|
|
100
|
+
added5: { value: value + 5 },
|
|
101
|
+
})),
|
|
102
|
+
/**
|
|
103
|
+
* @description This is possible, but not recommended to do. Because
|
|
104
|
+
* `multiply2` is a procedure on `ioServer`, this will trigger the
|
|
105
|
+
* `multiply2` procedure on `ioServer`. Connected peers will not
|
|
106
|
+
* receive `multiply2`, but rather `multipled2`.
|
|
107
|
+
*/
|
|
108
|
+
subtract5Multiply2: io.procedure
|
|
109
|
+
.input(z.object({ value: z.number() }))
|
|
110
|
+
.broadcast(({ value }) => ({
|
|
111
|
+
multiply2: { value: value - 5 },
|
|
112
|
+
})),
|
|
113
|
+
}),
|
|
114
|
+
});
|
|
115
|
+
```
|
|
116
|
+
|
|
117
|
+
- Updated dependencies [19ed36c]
|
|
118
|
+
- Updated dependencies [19ed36c]
|
|
119
|
+
- @pluv/client@0.27.0
|
|
120
|
+
- @pluv/crdt@0.27.0
|
|
121
|
+
- @pluv/types@0.27.0
|
|
122
|
+
|
|
123
|
+
## 0.26.0
|
|
124
|
+
|
|
125
|
+
### Minor Changes
|
|
126
|
+
|
|
127
|
+
- 19e5dda: **BREAKING**
|
|
128
|
+
Update `authEndpoint` and `wsEndpoint` to now use a parameterized object that passes through additional data via a `metadata` property.
|
|
129
|
+
|
|
130
|
+
```tsx
|
|
131
|
+
// Before
|
|
132
|
+
|
|
133
|
+
import { env } from "./env";
|
|
134
|
+
import type { ioServer } from "./server";
|
|
135
|
+
|
|
136
|
+
const client = createClient<typeof ioServer>({
|
|
137
|
+
authEndpoint: (room: string) => `${env.API_URL}}/room/${room}`,
|
|
138
|
+
wsEndpoint: (room: string) => `${env.WS_URL}/room/${room}`,
|
|
139
|
+
});
|
|
140
|
+
|
|
141
|
+
// After
|
|
142
|
+
|
|
143
|
+
const client = createClient<
|
|
144
|
+
typeof ioServer,
|
|
145
|
+
// Optional: You can specify types for metadata here. This is useful for Cloudflare Pages
|
|
146
|
+
{ apiUrl: string; wsUrl: string }
|
|
147
|
+
>({
|
|
148
|
+
authEndpoint: ({ metadata, room }) => `${metadata.apiUrl}}/room/${room}`,
|
|
149
|
+
wsEndpoint: ({ metadata, room }) => `${{ metadata.wsUrl }}/room/${room}`,
|
|
150
|
+
});
|
|
151
|
+
|
|
152
|
+
client.createRoom("my-room", {
|
|
153
|
+
// This property exists when the `metadata` generic type is defined above
|
|
154
|
+
metadata: {
|
|
155
|
+
apiUrl: "https://example.com/api",
|
|
156
|
+
wsUrl: "wss://example.com/api",
|
|
157
|
+
},
|
|
158
|
+
// ...
|
|
159
|
+
});
|
|
160
|
+
|
|
161
|
+
<PluvRoomProvider
|
|
162
|
+
// This property exists when the `metadata` generic type is defined above
|
|
163
|
+
metadata={{
|
|
164
|
+
apiUrl: "https://example.com/api",
|
|
165
|
+
wsUrl: "wss://example.com/api",
|
|
166
|
+
}}
|
|
167
|
+
>
|
|
168
|
+
{/* ... */}
|
|
169
|
+
</PluvRoomProvider>
|
|
170
|
+
```
|
|
171
|
+
|
|
172
|
+
### Patch Changes
|
|
173
|
+
|
|
174
|
+
- Updated dependencies [19e5dda]
|
|
175
|
+
- @pluv/client@0.26.0
|
|
176
|
+
- @pluv/crdt@0.26.0
|
|
177
|
+
- @pluv/types@0.26.0
|
|
178
|
+
|
|
3
179
|
## 0.25.4
|
|
4
180
|
|
|
5
181
|
### Patch Changes
|
package/dist/index.d.mts
CHANGED
|
@@ -1,15 +1,15 @@
|
|
|
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
3
|
import { CrdtType, AbstractCrdtDocFactory, 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, TPresence extends JsonObject = {}, TStorage extends Record<string, CrdtType<any, any>> = {}> = {
|
|
10
|
-
addons?: readonly PluvRoomAddon<TIO, TPresence, TStorage>[];
|
|
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
|
+
addons?: readonly PluvRoomAddon<TIO, TMetadata, TPresence, TStorage>[];
|
|
11
11
|
initialStorage?: AbstractCrdtDocFactory<TStorage>;
|
|
12
|
-
|
|
12
|
+
router?: PluvRouter<TIO, TPresence, TStorage, TEvents>;
|
|
13
13
|
};
|
|
14
14
|
type BaseRoomProviderProps<TPresence extends JsonObject, TStorage extends Record<string, CrdtType<any, any>>> = {
|
|
15
15
|
children?: ReactNode;
|
|
@@ -20,13 +20,17 @@ type BaseRoomProviderProps<TPresence extends JsonObject, TStorage extends Record
|
|
|
20
20
|
} : {
|
|
21
21
|
initialPresence: TPresence;
|
|
22
22
|
});
|
|
23
|
-
type MockedRoomProviderProps<TIO extends IOLike, TPresence extends JsonObject, TStorage extends Record<string, CrdtType<any, any
|
|
24
|
-
events?: MockedRoomEvents<TIO
|
|
23
|
+
type MockedRoomProviderProps<TIO extends IOLike, TPresence extends JsonObject, TStorage extends Record<string, CrdtType<any, any>>, TEvents extends PluvRouterEventConfig<TIO, TPresence, TStorage> = {}> = BaseRoomProviderProps<TPresence, TStorage> & {
|
|
24
|
+
events?: MockedRoomEvents<MergeEvents<TEvents, TIO>>;
|
|
25
25
|
};
|
|
26
|
-
type PluvRoomProviderProps<TIO extends IOLike, TPresence extends JsonObject, TStorage extends Record<string, CrdtType<any, any>>> = BaseRoomProviderProps<TPresence, TStorage> & {
|
|
26
|
+
type PluvRoomProviderProps<TIO extends IOLike, TMetadata extends JsonObject, TPresence extends JsonObject, TStorage extends Record<string, CrdtType<any, any>>> = BaseRoomProviderProps<TPresence, TStorage> & {
|
|
27
27
|
debug?: boolean | PluvRoomDebug<TIO>;
|
|
28
28
|
onAuthorizationFail?: (error: Error) => void;
|
|
29
|
-
}
|
|
29
|
+
} & (keyof TMetadata extends never ? {
|
|
30
|
+
metadata?: undefined;
|
|
31
|
+
} : {
|
|
32
|
+
metadata: TMetadata;
|
|
33
|
+
});
|
|
30
34
|
interface SubscriptionHookOptions<T extends unknown> {
|
|
31
35
|
isEqual?: (a: T, b: T) => boolean;
|
|
32
36
|
}
|
|
@@ -39,16 +43,16 @@ type EventProxy<TIO extends IOLike> = {
|
|
|
39
43
|
useEvent: (callback: (data: Id<IOEventMessage<TIO, event>>) => void) => void;
|
|
40
44
|
};
|
|
41
45
|
};
|
|
42
|
-
interface CreateRoomBundle<TIO extends IOLike, TPresence extends JsonObject, TStorage extends Record<string, CrdtType<any, any
|
|
46
|
+
interface CreateRoomBundle<TIO extends IOLike, TMetadata extends JsonObject, TPresence extends JsonObject, TStorage extends Record<string, CrdtType<any, any>>, TEvents extends PluvRouterEventConfig<TIO, TPresence, TStorage> = {}> {
|
|
43
47
|
MockedRoomProvider: FC<MockedRoomProviderProps<TIO, TPresence, TStorage>>;
|
|
44
|
-
PluvRoomProvider: FC<PluvRoomProviderProps<TIO, TPresence, TStorage>>;
|
|
45
|
-
event: EventProxy<TIO
|
|
46
|
-
useBroadcast: () => BroadcastProxy<TIO
|
|
48
|
+
PluvRoomProvider: FC<PluvRoomProviderProps<TIO, TMetadata, TPresence, TStorage>>;
|
|
49
|
+
event: EventProxy<MergeEvents<TEvents, TIO>>;
|
|
50
|
+
useBroadcast: () => BroadcastProxy<MergeEvents<TEvents, TIO>>;
|
|
47
51
|
useCanRedo: () => boolean;
|
|
48
52
|
useCanUndo: () => boolean;
|
|
49
53
|
useConnection: <T extends unknown = WebSocketConnection>(selector: (connection: WebSocketConnection) => T, options?: SubscriptionHookOptions<Id<T>>) => Id<T>;
|
|
50
54
|
useDoc: () => AbstractCrdtDoc<TStorage>;
|
|
51
|
-
useEvent: <TType extends keyof InferIOOutput<TIO
|
|
55
|
+
useEvent: <TType extends keyof InferIOOutput<MergeEvents<TEvents, TIO>>>(type: TType, callback: (data: Id<IOEventMessage<MergeEvents<TEvents, TIO>, TType>>) => void) => void;
|
|
52
56
|
useMyPresence: <T extends unknown = TPresence>(selector?: (myPresence: TPresence) => T, options?: SubscriptionHookOptions<Id<T> | null>) => [myPresence: Id<T>, updateMyPresence: Dispatch<UpdateMyPresenceAction<TPresence>>];
|
|
53
57
|
useMyself: <T extends unknown = UserInfo<TIO, TPresence>>(selector?: (myself: Id<UserInfo<TIO, TPresence>>) => T, options?: SubscriptionHookOptions<Id<T> | null>) => Id<T> | null;
|
|
54
58
|
useOther: <T extends unknown = UserInfo<TIO, TPresence>>(connectionId: string, selector?: (other: UserInfo<TIO, TPresence>) => T, options?: SubscriptionHookOptions<T | null>) => T | null;
|
|
@@ -59,16 +63,16 @@ interface CreateRoomBundle<TIO extends IOLike, TPresence extends JsonObject, TSt
|
|
|
59
63
|
useTransact: () => (fn: (storage: TStorage) => void, origin?: string) => void;
|
|
60
64
|
useUndo: () => () => void;
|
|
61
65
|
}
|
|
62
|
-
type InferRoomStorage<TRoomBundle extends CreateRoomBundle<any, any, any>> = TRoomBundle extends CreateRoomBundle<any, any, infer IStorage> ? IStorage : never;
|
|
66
|
+
type InferRoomStorage<TRoomBundle extends CreateRoomBundle<any, any, any, any, any>> = TRoomBundle extends CreateRoomBundle<any, any, any, infer IStorage> ? IStorage : never;
|
|
63
67
|
|
|
64
68
|
interface PluvProviderProps {
|
|
65
69
|
children?: ReactNode;
|
|
66
70
|
}
|
|
67
|
-
interface CreateBundle<TIO extends IOLike> {
|
|
68
|
-
createRoomBundle: <
|
|
71
|
+
interface CreateBundle<TIO extends IOLike, TMetadata extends JsonObject, TPresence extends JsonObject = {}, TStorage extends Record<string, CrdtType<any, any>> = {}> {
|
|
72
|
+
createRoomBundle: <TEvents extends PluvRouterEventConfig<TIO, TPresence, TStorage> = {}>(options: CreateRoomBundleOptions<TIO, TMetadata, TPresence, TStorage, TEvents>) => CreateRoomBundle<TIO, TMetadata, TPresence, TStorage, TEvents>;
|
|
69
73
|
PluvProvider: FC<PluvProviderProps>;
|
|
70
|
-
useClient: () => PluvClient<TIO>;
|
|
74
|
+
useClient: () => PluvClient<TIO, TPresence, TStorage, TMetadata>;
|
|
71
75
|
}
|
|
72
|
-
declare const createBundle: <TIO extends IOLike>(client: PluvClient<TIO>) => CreateBundle<TIO>;
|
|
76
|
+
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>;
|
|
73
77
|
|
|
74
78
|
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,15 @@
|
|
|
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
3
|
import { CrdtType, AbstractCrdtDocFactory, 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, TPresence extends JsonObject = {}, TStorage extends Record<string, CrdtType<any, any>> = {}> = {
|
|
10
|
-
addons?: readonly PluvRoomAddon<TIO, TPresence, TStorage>[];
|
|
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
|
+
addons?: readonly PluvRoomAddon<TIO, TMetadata, TPresence, TStorage>[];
|
|
11
11
|
initialStorage?: AbstractCrdtDocFactory<TStorage>;
|
|
12
|
-
|
|
12
|
+
router?: PluvRouter<TIO, TPresence, TStorage, TEvents>;
|
|
13
13
|
};
|
|
14
14
|
type BaseRoomProviderProps<TPresence extends JsonObject, TStorage extends Record<string, CrdtType<any, any>>> = {
|
|
15
15
|
children?: ReactNode;
|
|
@@ -20,13 +20,17 @@ type BaseRoomProviderProps<TPresence extends JsonObject, TStorage extends Record
|
|
|
20
20
|
} : {
|
|
21
21
|
initialPresence: TPresence;
|
|
22
22
|
});
|
|
23
|
-
type MockedRoomProviderProps<TIO extends IOLike, TPresence extends JsonObject, TStorage extends Record<string, CrdtType<any, any
|
|
24
|
-
events?: MockedRoomEvents<TIO
|
|
23
|
+
type MockedRoomProviderProps<TIO extends IOLike, TPresence extends JsonObject, TStorage extends Record<string, CrdtType<any, any>>, TEvents extends PluvRouterEventConfig<TIO, TPresence, TStorage> = {}> = BaseRoomProviderProps<TPresence, TStorage> & {
|
|
24
|
+
events?: MockedRoomEvents<MergeEvents<TEvents, TIO>>;
|
|
25
25
|
};
|
|
26
|
-
type PluvRoomProviderProps<TIO extends IOLike, TPresence extends JsonObject, TStorage extends Record<string, CrdtType<any, any>>> = BaseRoomProviderProps<TPresence, TStorage> & {
|
|
26
|
+
type PluvRoomProviderProps<TIO extends IOLike, TMetadata extends JsonObject, TPresence extends JsonObject, TStorage extends Record<string, CrdtType<any, any>>> = BaseRoomProviderProps<TPresence, TStorage> & {
|
|
27
27
|
debug?: boolean | PluvRoomDebug<TIO>;
|
|
28
28
|
onAuthorizationFail?: (error: Error) => void;
|
|
29
|
-
}
|
|
29
|
+
} & (keyof TMetadata extends never ? {
|
|
30
|
+
metadata?: undefined;
|
|
31
|
+
} : {
|
|
32
|
+
metadata: TMetadata;
|
|
33
|
+
});
|
|
30
34
|
interface SubscriptionHookOptions<T extends unknown> {
|
|
31
35
|
isEqual?: (a: T, b: T) => boolean;
|
|
32
36
|
}
|
|
@@ -39,16 +43,16 @@ type EventProxy<TIO extends IOLike> = {
|
|
|
39
43
|
useEvent: (callback: (data: Id<IOEventMessage<TIO, event>>) => void) => void;
|
|
40
44
|
};
|
|
41
45
|
};
|
|
42
|
-
interface CreateRoomBundle<TIO extends IOLike, TPresence extends JsonObject, TStorage extends Record<string, CrdtType<any, any
|
|
46
|
+
interface CreateRoomBundle<TIO extends IOLike, TMetadata extends JsonObject, TPresence extends JsonObject, TStorage extends Record<string, CrdtType<any, any>>, TEvents extends PluvRouterEventConfig<TIO, TPresence, TStorage> = {}> {
|
|
43
47
|
MockedRoomProvider: FC<MockedRoomProviderProps<TIO, TPresence, TStorage>>;
|
|
44
|
-
PluvRoomProvider: FC<PluvRoomProviderProps<TIO, TPresence, TStorage>>;
|
|
45
|
-
event: EventProxy<TIO
|
|
46
|
-
useBroadcast: () => BroadcastProxy<TIO
|
|
48
|
+
PluvRoomProvider: FC<PluvRoomProviderProps<TIO, TMetadata, TPresence, TStorage>>;
|
|
49
|
+
event: EventProxy<MergeEvents<TEvents, TIO>>;
|
|
50
|
+
useBroadcast: () => BroadcastProxy<MergeEvents<TEvents, TIO>>;
|
|
47
51
|
useCanRedo: () => boolean;
|
|
48
52
|
useCanUndo: () => boolean;
|
|
49
53
|
useConnection: <T extends unknown = WebSocketConnection>(selector: (connection: WebSocketConnection) => T, options?: SubscriptionHookOptions<Id<T>>) => Id<T>;
|
|
50
54
|
useDoc: () => AbstractCrdtDoc<TStorage>;
|
|
51
|
-
useEvent: <TType extends keyof InferIOOutput<TIO
|
|
55
|
+
useEvent: <TType extends keyof InferIOOutput<MergeEvents<TEvents, TIO>>>(type: TType, callback: (data: Id<IOEventMessage<MergeEvents<TEvents, TIO>, TType>>) => void) => void;
|
|
52
56
|
useMyPresence: <T extends unknown = TPresence>(selector?: (myPresence: TPresence) => T, options?: SubscriptionHookOptions<Id<T> | null>) => [myPresence: Id<T>, updateMyPresence: Dispatch<UpdateMyPresenceAction<TPresence>>];
|
|
53
57
|
useMyself: <T extends unknown = UserInfo<TIO, TPresence>>(selector?: (myself: Id<UserInfo<TIO, TPresence>>) => T, options?: SubscriptionHookOptions<Id<T> | null>) => Id<T> | null;
|
|
54
58
|
useOther: <T extends unknown = UserInfo<TIO, TPresence>>(connectionId: string, selector?: (other: UserInfo<TIO, TPresence>) => T, options?: SubscriptionHookOptions<T | null>) => T | null;
|
|
@@ -59,16 +63,16 @@ interface CreateRoomBundle<TIO extends IOLike, TPresence extends JsonObject, TSt
|
|
|
59
63
|
useTransact: () => (fn: (storage: TStorage) => void, origin?: string) => void;
|
|
60
64
|
useUndo: () => () => void;
|
|
61
65
|
}
|
|
62
|
-
type InferRoomStorage<TRoomBundle extends CreateRoomBundle<any, any, any>> = TRoomBundle extends CreateRoomBundle<any, any, infer IStorage> ? IStorage : never;
|
|
66
|
+
type InferRoomStorage<TRoomBundle extends CreateRoomBundle<any, any, any, any, any>> = TRoomBundle extends CreateRoomBundle<any, any, any, infer IStorage> ? IStorage : never;
|
|
63
67
|
|
|
64
68
|
interface PluvProviderProps {
|
|
65
69
|
children?: ReactNode;
|
|
66
70
|
}
|
|
67
|
-
interface CreateBundle<TIO extends IOLike> {
|
|
68
|
-
createRoomBundle: <
|
|
71
|
+
interface CreateBundle<TIO extends IOLike, TMetadata extends JsonObject, TPresence extends JsonObject = {}, TStorage extends Record<string, CrdtType<any, any>> = {}> {
|
|
72
|
+
createRoomBundle: <TEvents extends PluvRouterEventConfig<TIO, TPresence, TStorage> = {}>(options: CreateRoomBundleOptions<TIO, TMetadata, TPresence, TStorage, TEvents>) => CreateRoomBundle<TIO, TMetadata, TPresence, TStorage, TEvents>;
|
|
69
73
|
PluvProvider: FC<PluvProviderProps>;
|
|
70
|
-
useClient: () => PluvClient<TIO>;
|
|
74
|
+
useClient: () => PluvClient<TIO, TPresence, TStorage, TMetadata>;
|
|
71
75
|
}
|
|
72
|
-
declare const createBundle: <TIO extends IOLike>(client: PluvClient<TIO>) => CreateBundle<TIO>;
|
|
76
|
+
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>;
|
|
73
77
|
|
|
74
78
|
export { type CreateBundle, type CreateRoomBundle, type CreateRoomBundleOptions, type InferRoomStorage, type PluvProviderProps, type PluvRoomProviderProps, type SubscriptionHookOptions, createBundle };
|
package/dist/index.js
CHANGED
|
@@ -122,15 +122,14 @@ var createRoomBundle = (client, options) => {
|
|
|
122
122
|
return new import_client.MockedRoom(_room, {
|
|
123
123
|
events,
|
|
124
124
|
initialPresence,
|
|
125
|
-
initialStorage: typeof initialStorage === "function" ? _initialStorage.getFactory(initialStorage) : _initialStorage
|
|
126
|
-
presence: options.presence
|
|
125
|
+
initialStorage: typeof initialStorage === "function" ? _initialStorage.getFactory(initialStorage) : _initialStorage
|
|
127
126
|
});
|
|
128
127
|
});
|
|
129
128
|
return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(MockedRoomContext.Provider, { value: { room }, children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(PluvRoomContext.Provider, { value: room, children }) });
|
|
130
129
|
});
|
|
131
130
|
MockedRoomProvider.displayName = "MockedRoomProvider";
|
|
132
131
|
const PluvRoomProvider = (0, import_react4.memo)((props) => {
|
|
133
|
-
const { children, debug, initialPresence, initialStorage, onAuthorizationFail, room: _room } = props;
|
|
132
|
+
const { children, debug, initialPresence, initialStorage, metadata, onAuthorizationFail, room: _room } = props;
|
|
134
133
|
const rerender = useRerender();
|
|
135
134
|
const { room: mockedRoom } = (0, import_react4.useContext)(MockedRoomContext);
|
|
136
135
|
const [room] = (0, import_react4.useState)(() => {
|
|
@@ -139,8 +138,9 @@ var createRoomBundle = (client, options) => {
|
|
|
139
138
|
debug,
|
|
140
139
|
initialPresence,
|
|
141
140
|
initialStorage: typeof initialStorage === "function" ? _initialStorage.getFactory(initialStorage) : _initialStorage,
|
|
142
|
-
|
|
143
|
-
onAuthorizationFail
|
|
141
|
+
metadata,
|
|
142
|
+
onAuthorizationFail,
|
|
143
|
+
router: options.router
|
|
144
144
|
});
|
|
145
145
|
});
|
|
146
146
|
(0, import_react4.useEffect)(() => {
|
package/dist/index.mjs
CHANGED
|
@@ -86,15 +86,14 @@ var createRoomBundle = (client, options) => {
|
|
|
86
86
|
return new MockedRoom(_room, {
|
|
87
87
|
events,
|
|
88
88
|
initialPresence,
|
|
89
|
-
initialStorage: typeof initialStorage === "function" ? _initialStorage.getFactory(initialStorage) : _initialStorage
|
|
90
|
-
presence: options.presence
|
|
89
|
+
initialStorage: typeof initialStorage === "function" ? _initialStorage.getFactory(initialStorage) : _initialStorage
|
|
91
90
|
});
|
|
92
91
|
});
|
|
93
92
|
return /* @__PURE__ */ jsx(MockedRoomContext.Provider, { value: { room }, children: /* @__PURE__ */ jsx(PluvRoomContext.Provider, { value: room, children }) });
|
|
94
93
|
});
|
|
95
94
|
MockedRoomProvider.displayName = "MockedRoomProvider";
|
|
96
95
|
const PluvRoomProvider = memo((props) => {
|
|
97
|
-
const { children, debug, initialPresence, initialStorage, onAuthorizationFail, room: _room } = props;
|
|
96
|
+
const { children, debug, initialPresence, initialStorage, metadata, onAuthorizationFail, room: _room } = props;
|
|
98
97
|
const rerender = useRerender();
|
|
99
98
|
const { room: mockedRoom } = useContext(MockedRoomContext);
|
|
100
99
|
const [room] = useState3(() => {
|
|
@@ -103,8 +102,9 @@ var createRoomBundle = (client, options) => {
|
|
|
103
102
|
debug,
|
|
104
103
|
initialPresence,
|
|
105
104
|
initialStorage: typeof initialStorage === "function" ? _initialStorage.getFactory(initialStorage) : _initialStorage,
|
|
106
|
-
|
|
107
|
-
onAuthorizationFail
|
|
105
|
+
metadata,
|
|
106
|
+
onAuthorizationFail,
|
|
107
|
+
router: options.router
|
|
108
108
|
});
|
|
109
109
|
});
|
|
110
110
|
useEffect2(() => {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@pluv/react",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.27.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/
|
|
22
|
-
"@pluv/
|
|
23
|
-
"@pluv/
|
|
21
|
+
"@pluv/crdt": "^0.27.0",
|
|
22
|
+
"@pluv/types": "^0.27.0",
|
|
23
|
+
"@pluv/client": "^0.27.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.27.0",
|
|
36
|
+
"eslint-config-pluv": "^0.27.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,20 +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, TPresence, TStorage>,
|
|
17
|
-
) => CreateRoomBundle<TIO, 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>;
|
|
28
|
+
useClient: () => PluvClient<TIO, TPresence, TStorage, TMetadata>;
|
|
24
29
|
}
|
|
25
30
|
|
|
26
|
-
export const createBundle = <
|
|
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> => {
|
|
27
39
|
/**
|
|
28
40
|
* !HACK
|
|
29
41
|
* @description We'll let the context error out if client is not provided,
|
|
@@ -31,7 +43,7 @@ export const createBundle = <TIO extends IOLike>(client: PluvClient<TIO>): Creat
|
|
|
31
43
|
* @author leedavidcs
|
|
32
44
|
* @date October 27, 2022
|
|
33
45
|
*/
|
|
34
|
-
const PluvContext = createContext<PluvClient<
|
|
46
|
+
const PluvContext = createContext<PluvClient<TIO, TPresence, TStorage, TMetadata>>(null as any);
|
|
35
47
|
|
|
36
48
|
const PluvProvider = memo<PluvProviderProps>((props) => {
|
|
37
49
|
const { children } = props;
|
|
@@ -41,14 +53,11 @@ export const createBundle = <TIO extends IOLike>(client: PluvClient<TIO>): Creat
|
|
|
41
53
|
|
|
42
54
|
PluvProvider.displayName = "PluvProvider";
|
|
43
55
|
|
|
44
|
-
const useClient = (): PluvClient<TIO> => useContext(PluvContext);
|
|
56
|
+
const useClient = (): PluvClient<TIO, TPresence, TStorage, TMetadata> => useContext(PluvContext);
|
|
45
57
|
|
|
46
|
-
const createRoomBundle = <
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
>(
|
|
50
|
-
options: CreateRoomBundleOptions<TIO, TPresence, TStorage>,
|
|
51
|
-
): CreateRoomBundle<TIO, 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);
|
|
52
61
|
|
|
53
62
|
return {
|
|
54
63
|
createRoomBundle,
|
package/src/createRoomBundle.tsx
CHANGED
|
@@ -1,17 +1,21 @@
|
|
|
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,
|
|
10
|
+
PluvRouter,
|
|
11
|
+
PluvRouterEventConfig,
|
|
8
12
|
UserInfo,
|
|
9
13
|
WebSocketConnection,
|
|
10
14
|
} from "@pluv/client";
|
|
11
15
|
import { MockedRoom } from "@pluv/client";
|
|
12
16
|
import type { AbstractCrdtDoc, AbstractCrdtDocFactory, CrdtType, InferCrdtJson } from "@pluv/crdt";
|
|
13
17
|
import { noop } from "@pluv/crdt";
|
|
14
|
-
import type { IOEventMessage, IOLike, Id, InferIOInput, InferIOOutput,
|
|
18
|
+
import type { IOEventMessage, IOLike, Id, InferIOInput, InferIOOutput, JsonObject } from "@pluv/types";
|
|
15
19
|
import fastDeepEqual from "fast-deep-equal";
|
|
16
20
|
import type { Dispatch, FC, ReactNode } from "react";
|
|
17
21
|
import { createContext, memo, useCallback, useContext, useEffect, useMemo, useState } from "react";
|
|
@@ -19,12 +23,14 @@ import { identity, shallowArrayEqual, useRerender, useSyncExternalStoreWithSelec
|
|
|
19
23
|
|
|
20
24
|
export type CreateRoomBundleOptions<
|
|
21
25
|
TIO extends IOLike,
|
|
26
|
+
TMetadata extends JsonObject = {},
|
|
22
27
|
TPresence extends JsonObject = {},
|
|
23
28
|
TStorage extends Record<string, CrdtType<any, any>> = {},
|
|
29
|
+
TEvents extends PluvRouterEventConfig<TIO, TPresence, TStorage> = {},
|
|
24
30
|
> = {
|
|
25
|
-
addons?: readonly PluvRoomAddon<TIO, TPresence, TStorage>[];
|
|
31
|
+
addons?: readonly PluvRoomAddon<TIO, TMetadata, TPresence, TStorage>[];
|
|
26
32
|
initialStorage?: AbstractCrdtDocFactory<TStorage>;
|
|
27
|
-
|
|
33
|
+
router?: PluvRouter<TIO, TPresence, TStorage, TEvents>;
|
|
28
34
|
};
|
|
29
35
|
|
|
30
36
|
type BaseRoomProviderProps<TPresence extends JsonObject, TStorage extends Record<string, CrdtType<any, any>>> = {
|
|
@@ -37,18 +43,20 @@ export type MockedRoomProviderProps<
|
|
|
37
43
|
TIO extends IOLike,
|
|
38
44
|
TPresence extends JsonObject,
|
|
39
45
|
TStorage extends Record<string, CrdtType<any, any>>,
|
|
46
|
+
TEvents extends PluvRouterEventConfig<TIO, TPresence, TStorage> = {},
|
|
40
47
|
> = BaseRoomProviderProps<TPresence, TStorage> & {
|
|
41
|
-
events?: MockedRoomEvents<TIO
|
|
48
|
+
events?: MockedRoomEvents<MergeEvents<TEvents, TIO>>;
|
|
42
49
|
};
|
|
43
50
|
|
|
44
51
|
export type PluvRoomProviderProps<
|
|
45
52
|
TIO extends IOLike,
|
|
53
|
+
TMetadata extends JsonObject,
|
|
46
54
|
TPresence extends JsonObject,
|
|
47
55
|
TStorage extends Record<string, CrdtType<any, any>>,
|
|
48
56
|
> = BaseRoomProviderProps<TPresence, TStorage> & {
|
|
49
57
|
debug?: boolean | PluvRoomDebug<TIO>;
|
|
50
58
|
onAuthorizationFail?: (error: Error) => void;
|
|
51
|
-
};
|
|
59
|
+
} & (keyof TMetadata extends never ? { metadata?: undefined } : { metadata: TMetadata });
|
|
52
60
|
|
|
53
61
|
export interface SubscriptionHookOptions<T extends unknown> {
|
|
54
62
|
isEqual?: (a: T, b: T) => boolean;
|
|
@@ -73,18 +81,20 @@ export type EventProxy<TIO extends IOLike> = {
|
|
|
73
81
|
|
|
74
82
|
export interface CreateRoomBundle<
|
|
75
83
|
TIO extends IOLike,
|
|
84
|
+
TMetadata extends JsonObject,
|
|
76
85
|
TPresence extends JsonObject,
|
|
77
86
|
TStorage extends Record<string, CrdtType<any, any>>,
|
|
87
|
+
TEvents extends PluvRouterEventConfig<TIO, TPresence, TStorage> = {},
|
|
78
88
|
> {
|
|
79
89
|
// components
|
|
80
90
|
MockedRoomProvider: FC<MockedRoomProviderProps<TIO, TPresence, TStorage>>;
|
|
81
|
-
PluvRoomProvider: FC<PluvRoomProviderProps<TIO, TPresence, TStorage>>;
|
|
91
|
+
PluvRoomProvider: FC<PluvRoomProviderProps<TIO, TMetadata, TPresence, TStorage>>;
|
|
82
92
|
|
|
83
93
|
// proxies
|
|
84
|
-
event: EventProxy<TIO
|
|
94
|
+
event: EventProxy<MergeEvents<TEvents, TIO>>;
|
|
85
95
|
|
|
86
96
|
// hooks
|
|
87
|
-
useBroadcast: () => BroadcastProxy<TIO
|
|
97
|
+
useBroadcast: () => BroadcastProxy<MergeEvents<TEvents, TIO>>;
|
|
88
98
|
useCanRedo: () => boolean;
|
|
89
99
|
useCanUndo: () => boolean;
|
|
90
100
|
useConnection: <T extends unknown = WebSocketConnection>(
|
|
@@ -92,9 +102,9 @@ export interface CreateRoomBundle<
|
|
|
92
102
|
options?: SubscriptionHookOptions<Id<T>>,
|
|
93
103
|
) => Id<T>;
|
|
94
104
|
useDoc: () => AbstractCrdtDoc<TStorage>;
|
|
95
|
-
useEvent: <TType extends keyof InferIOOutput<TIO
|
|
105
|
+
useEvent: <TType extends keyof InferIOOutput<MergeEvents<TEvents, TIO>>>(
|
|
96
106
|
type: TType,
|
|
97
|
-
callback: (data: Id<IOEventMessage<
|
|
107
|
+
callback: (data: Id<IOEventMessage<MergeEvents<TEvents, TIO>, TType>>) => void,
|
|
98
108
|
) => void;
|
|
99
109
|
useMyPresence: <T extends unknown = TPresence>(
|
|
100
110
|
selector?: (myPresence: TPresence) => T,
|
|
@@ -124,17 +134,19 @@ export interface CreateRoomBundle<
|
|
|
124
134
|
useUndo: () => () => void;
|
|
125
135
|
}
|
|
126
136
|
|
|
127
|
-
export type InferRoomStorage<TRoomBundle extends CreateRoomBundle<any, any, any>> =
|
|
128
|
-
TRoomBundle extends CreateRoomBundle<any, any, infer IStorage> ? IStorage : never;
|
|
137
|
+
export type InferRoomStorage<TRoomBundle extends CreateRoomBundle<any, any, any, any, any>> =
|
|
138
|
+
TRoomBundle extends CreateRoomBundle<any, any, any, infer IStorage> ? IStorage : never;
|
|
129
139
|
|
|
130
140
|
export const createRoomBundle = <
|
|
131
141
|
TIO extends IOLike,
|
|
142
|
+
TMetadata extends JsonObject = {},
|
|
132
143
|
TPresence extends JsonObject = {},
|
|
133
144
|
TStorage extends Record<string, CrdtType<any, any>> = {},
|
|
145
|
+
TEvents extends PluvRouterEventConfig<TIO, TPresence, TStorage> = {},
|
|
134
146
|
>(
|
|
135
|
-
client: PluvClient<TIO>,
|
|
136
|
-
options: CreateRoomBundleOptions<TIO, TPresence, TStorage>,
|
|
137
|
-
): CreateRoomBundle<TIO, TPresence, TStorage> => {
|
|
147
|
+
client: PluvClient<TIO, TPresence, TStorage, TMetadata>,
|
|
148
|
+
options: CreateRoomBundleOptions<TIO, TMetadata, TPresence, TStorage, TEvents>,
|
|
149
|
+
): CreateRoomBundle<TIO, TMetadata, TPresence, TStorage, TEvents> => {
|
|
138
150
|
const _initialStorage = (options.initialStorage ?? noop.doc()) as AbstractCrdtDocFactory<TStorage>;
|
|
139
151
|
|
|
140
152
|
/**
|
|
@@ -153,13 +165,12 @@ export const createRoomBundle = <
|
|
|
153
165
|
const MockedRoomProvider = memo<MockedRoomProviderProps<TIO, TPresence, TStorage>>((props) => {
|
|
154
166
|
const { children, events, initialPresence, initialStorage, room: _room } = props;
|
|
155
167
|
|
|
156
|
-
const [room] = useState<MockedRoom<TIO, TPresence, TStorage>>(() => {
|
|
157
|
-
return new MockedRoom<TIO, TPresence, TStorage>(_room, {
|
|
168
|
+
const [room] = useState<MockedRoom<TIO, TPresence, TStorage, TEvents>>(() => {
|
|
169
|
+
return new MockedRoom<TIO, TPresence, TStorage, TEvents>(_room, {
|
|
158
170
|
events,
|
|
159
171
|
initialPresence,
|
|
160
172
|
initialStorage:
|
|
161
173
|
typeof initialStorage === "function" ? _initialStorage.getFactory(initialStorage) : _initialStorage,
|
|
162
|
-
presence: options.presence,
|
|
163
174
|
});
|
|
164
175
|
});
|
|
165
176
|
|
|
@@ -172,22 +183,23 @@ export const createRoomBundle = <
|
|
|
172
183
|
|
|
173
184
|
MockedRoomProvider.displayName = "MockedRoomProvider";
|
|
174
185
|
|
|
175
|
-
const PluvRoomProvider = memo<PluvRoomProviderProps<TIO, TPresence, TStorage>>((props) => {
|
|
176
|
-
const { children, debug, initialPresence, initialStorage, onAuthorizationFail, room: _room } = props;
|
|
186
|
+
const PluvRoomProvider = memo<PluvRoomProviderProps<TIO, TMetadata, TPresence, TStorage>>((props) => {
|
|
187
|
+
const { children, debug, initialPresence, initialStorage, metadata, onAuthorizationFail, room: _room } = props;
|
|
177
188
|
|
|
178
189
|
const rerender = useRerender();
|
|
179
190
|
const { room: mockedRoom } = useContext(MockedRoomContext);
|
|
180
191
|
|
|
181
|
-
const [room] = useState<PluvRoom<TIO, TPresence, TStorage>>(() => {
|
|
182
|
-
return client.createRoom
|
|
192
|
+
const [room] = useState<PluvRoom<TIO, TMetadata, TPresence, TStorage, TEvents>>(() => {
|
|
193
|
+
return client.createRoom(_room, {
|
|
183
194
|
addons: options.addons,
|
|
184
195
|
debug,
|
|
185
196
|
initialPresence,
|
|
186
197
|
initialStorage:
|
|
187
198
|
typeof initialStorage === "function" ? _initialStorage.getFactory(initialStorage) : _initialStorage,
|
|
188
|
-
|
|
199
|
+
metadata,
|
|
189
200
|
onAuthorizationFail,
|
|
190
|
-
|
|
201
|
+
router: options.router,
|
|
202
|
+
} as CreateRoomOptions<TIO, TPresence, TStorage, TMetadata, TEvents>);
|
|
191
203
|
});
|
|
192
204
|
|
|
193
205
|
useEffect(() => {
|
|
@@ -215,24 +227,31 @@ export const createRoomBundle = <
|
|
|
215
227
|
|
|
216
228
|
const useRoom = () => useContext(PluvRoomContext);
|
|
217
229
|
|
|
218
|
-
const useBroadcast = (): BroadcastProxy<TIO
|
|
230
|
+
const useBroadcast = (): BroadcastProxy<MergeEvents<TEvents, TIO>> => {
|
|
219
231
|
const room = useRoom();
|
|
220
232
|
|
|
221
233
|
const broadcast = useCallback(
|
|
222
|
-
<TEvent extends keyof InferIOInput<
|
|
234
|
+
<TEvent extends keyof InferIOInput<MergeEvents<TEvents, TIO>>>(
|
|
235
|
+
event: TEvent,
|
|
236
|
+
data: Id<InferIOInput<MergeEvents<TEvents, TIO>>[TEvent]>,
|
|
237
|
+
) => {
|
|
223
238
|
room.broadcast(event, data);
|
|
224
239
|
},
|
|
225
240
|
[room],
|
|
226
241
|
);
|
|
227
242
|
|
|
228
|
-
return useMemo((): BroadcastProxy<TIO
|
|
243
|
+
return useMemo((): BroadcastProxy<MergeEvents<TEvents, TIO>> => {
|
|
229
244
|
return new Proxy(broadcast, {
|
|
230
245
|
get(fn, prop) {
|
|
231
|
-
return (
|
|
232
|
-
|
|
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);
|
|
233
252
|
};
|
|
234
253
|
},
|
|
235
|
-
}) as BroadcastProxy<TIO
|
|
254
|
+
}) as BroadcastProxy<MergeEvents<TEvents, TIO>>;
|
|
236
255
|
}, [broadcast]);
|
|
237
256
|
};
|
|
238
257
|
|
|
@@ -292,9 +311,9 @@ export const createRoomBundle = <
|
|
|
292
311
|
return room.getDoc();
|
|
293
312
|
};
|
|
294
313
|
|
|
295
|
-
const useEvent = <TType extends keyof InferIOOutput<TIO
|
|
314
|
+
const useEvent = <TType extends keyof InferIOOutput<MergeEvents<TEvents, TIO>>>(
|
|
296
315
|
type: TType,
|
|
297
|
-
callback: (data: Id<IOEventMessage<
|
|
316
|
+
callback: (data: Id<IOEventMessage<MergeEvents<TEvents, TIO>, TType>>) => void,
|
|
298
317
|
): void => {
|
|
299
318
|
const room = useRoom();
|
|
300
319
|
|
|
@@ -312,15 +331,19 @@ export const createRoomBundle = <
|
|
|
312
331
|
{
|
|
313
332
|
get(_, prop) {
|
|
314
333
|
const useProxyEvent = (
|
|
315
|
-
callback: (
|
|
334
|
+
callback: (
|
|
335
|
+
data: Id<
|
|
336
|
+
IOEventMessage<MergeEvents<TEvents, TIO>, keyof InferIOOutput<MergeEvents<TEvents, TIO>>>
|
|
337
|
+
>,
|
|
338
|
+
) => void,
|
|
316
339
|
): void => {
|
|
317
|
-
return useEvent(prop as keyof InferIOOutput<TIO
|
|
340
|
+
return useEvent(prop as keyof InferIOOutput<MergeEvents<TEvents, TIO>>, callback);
|
|
318
341
|
};
|
|
319
342
|
|
|
320
343
|
return { useEvent: useProxyEvent };
|
|
321
344
|
},
|
|
322
345
|
},
|
|
323
|
-
) as EventProxy<TIO
|
|
346
|
+
) as EventProxy<MergeEvents<TEvents, TIO>>;
|
|
324
347
|
|
|
325
348
|
const useMyPresence = <T extends unknown = TPresence>(
|
|
326
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";
|