@pluv/client 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.
@@ -1,18 +1,18 @@
1
1
 
2
- > @pluv/client@0.25.4 build /home/runner/work/pluv/pluv/packages/client
2
+ > @pluv/client@0.27.0 build /home/runner/work/pluv/pluv/packages/client
3
3
  > tsup src/index.ts --format esm,cjs --dts
4
4
 
5
5
  CLI Building entry: src/index.ts
6
6
  CLI Using tsconfig: tsconfig.json
7
- CLI tsup v8.2.4
7
+ CLI tsup v8.3.0
8
8
  CLI Target: es6
9
9
  ESM Build start
10
10
  CJS Build start
11
- CJS dist/index.js 43.49 KB
12
- CJS ⚡️ Build success in 146ms
13
- ESM dist/index.mjs 42.22 KB
14
- ESM ⚡️ Build success in 146ms
11
+ CJS dist/index.js 47.68 KB
12
+ CJS ⚡️ Build success in 129ms
13
+ ESM dist/index.mjs 46.42 KB
14
+ ESM ⚡️ Build success in 130ms
15
15
  DTS Build start
16
- DTS ⚡️ Build success in 3137ms
17
- DTS dist/index.d.mts 14.60 KB
18
- DTS dist/index.d.ts 14.60 KB
16
+ DTS ⚡️ Build success in 3681ms
17
+ DTS dist/index.d.mts 21.97 KB
18
+ DTS dist/index.d.ts 21.97 KB
package/CHANGELOG.md CHANGED
@@ -1,5 +1,184 @@
1
1
  # @pluv/client
2
2
 
3
+ ## 0.27.0
4
+
5
+ ### Minor Changes
6
+
7
+ - 19ed36c: **BREAKNG**
8
+
9
+ Updated `createClient` and `PluvClient.createRoom` object params to better support automatic type inference.
10
+
11
+ ```ts
12
+ // Before
13
+ import { createClient } from "@pluv/client";
14
+ import { yjs } from "@pluv/crdt-yjs";
15
+ import { z } from "zod";
16
+ import type { ioServer } from "./server/ioServer";
17
+
18
+ const client = createClient<typeof ioServer>({
19
+ authEndpoint: ({ room }) => "MY_AUTH_URL",
20
+ wsEndpoint: ({ room }) => "MY_WEBSOCKET_URL",
21
+ });
22
+
23
+ client.createRoom("my-example-room", {
24
+ presence: z.object({
25
+ selectionId: z.string().nullish(),
26
+ }),
27
+ initialPresence: {
28
+ selectionId: null,
29
+ },
30
+ initialStorage: yjs.doc(() => ({
31
+ messages: yjs.array<string>([]),
32
+ })),
33
+ });
34
+
35
+ // After
36
+ const client = createClient({
37
+ authEndpoint: ({ room }) => "MY_AUTH_URL",
38
+ wsEndpoint: ({ room }) => "MY_WEBSOCKET_URL",
39
+ /**
40
+ * @description The ioServer type now needs to be inferred on this property
41
+ * instead of within the generic on `createClient`. This is because of
42
+ * limitations with TypeScript not yet supporting partial type-inference
43
+ * for generics. Ensure to no-loonger include any generics on `createClient`
44
+ */
45
+ infer: (i) => ({ io: i<typeof ioServer> }),
46
+ // Now moved to `createClient` from `PluvClient.createRoom`
47
+ presence: z.object({
48
+ selectionId: z.string().nullish(),
49
+ }),
50
+ /**
51
+ * @description Now added to `createClient` to specify defaults for all
52
+ * rooms, and to infer types for storage. This value will be overwritten by
53
+ * `PluvClient.createRoom`.
54
+ */
55
+ initialStorage: yjs.doc(() => ({
56
+ messages: yjs.array<string>([]),
57
+ })),
58
+ });
59
+
60
+ const room = client.createRoom("my-example-room", {
61
+ initialPresence: {
62
+ selectionId: null,
63
+ },
64
+ initialStorage: yjs.doc(() => ({
65
+ messages: yjs.array<string>([]),
66
+ })),
67
+ });
68
+ ```
69
+
70
+ ### Patch Changes
71
+
72
+ - 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.
73
+
74
+ ```ts
75
+ // Backend Server
76
+ import { createIO } from "@pluv/io";
77
+
78
+ const io = createIO({
79
+ /* ... */
80
+ });
81
+ const ioServer = io.server({
82
+ router: io.router({
83
+ multiply2: io.procedure
84
+ .input(z.object({ value: z.number() }))
85
+ .broadcast(({ value }) => ({
86
+ multiplied2: { value: value * 2 },
87
+ })),
88
+ }),
89
+ });
90
+
91
+ // Frontend Client
92
+ import { createClient } from "@pluv/client";
93
+
94
+ const io = createClient({
95
+ /* ... */
96
+ });
97
+
98
+ const room = io.createRoom("my-example-room", {
99
+ // ...
100
+ router: io.router({
101
+ add5: io.procedure
102
+ .input(z.object({ value: z.number() }))
103
+ .broadcast(({ value }) => ({
104
+ /**
105
+ * @description Because `ioServer` does not specify `added5`,
106
+ * this will be forwarded to connected peers.
107
+ */
108
+ added5: { value: value + 5 },
109
+ })),
110
+ /**
111
+ * @description This is possible, but not recommended to do. Because
112
+ * `multiply2` is a procedure on `ioServer`, this will trigger the
113
+ * `multiply2` procedure on `ioServer`. Connected peers will not
114
+ * receive `multiply2`, but rather `multipled2`.
115
+ */
116
+ subtract5Multiply2: io.procedure
117
+ .input(z.object({ value: z.number() }))
118
+ .broadcast(({ value }) => ({
119
+ multiply2: { value: value - 5 },
120
+ })),
121
+ }),
122
+ });
123
+ ```
124
+
125
+ - @pluv/crdt@0.27.0
126
+ - @pluv/types@0.27.0
127
+
128
+ ## 0.26.0
129
+
130
+ ### Minor Changes
131
+
132
+ - 19e5dda: **BREAKING**
133
+ Update `authEndpoint` and `wsEndpoint` to now use a parameterized object that passes through additional data via a `metadata` property.
134
+
135
+ ```tsx
136
+ // Before
137
+
138
+ import { env } from "./env";
139
+ import type { ioServer } from "./server";
140
+
141
+ const client = createClient<typeof ioServer>({
142
+ authEndpoint: (room: string) => `${env.API_URL}}/room/${room}`,
143
+ wsEndpoint: (room: string) => `${env.WS_URL}/room/${room}`,
144
+ });
145
+
146
+ // After
147
+
148
+ const client = createClient<
149
+ typeof ioServer,
150
+ // Optional: You can specify types for metadata here. This is useful for Cloudflare Pages
151
+ { apiUrl: string; wsUrl: string }
152
+ >({
153
+ authEndpoint: ({ metadata, room }) => `${metadata.apiUrl}}/room/${room}`,
154
+ wsEndpoint: ({ metadata, room }) => `${{ metadata.wsUrl }}/room/${room}`,
155
+ });
156
+
157
+ client.createRoom("my-room", {
158
+ // This property exists when the `metadata` generic type is defined above
159
+ metadata: {
160
+ apiUrl: "https://example.com/api",
161
+ wsUrl: "wss://example.com/api",
162
+ },
163
+ // ...
164
+ });
165
+
166
+ <PluvRoomProvider
167
+ // This property exists when the `metadata` generic type is defined above
168
+ metadata={{
169
+ apiUrl: "https://example.com/api",
170
+ wsUrl: "wss://example.com/api",
171
+ }}
172
+ >
173
+ {/* ... */}
174
+ </PluvRoomProvider>
175
+ ```
176
+
177
+ ### Patch Changes
178
+
179
+ - @pluv/crdt@0.26.0
180
+ - @pluv/types@0.26.0
181
+
3
182
  ## 0.25.4
4
183
 
5
184
  ### Patch Changes
package/dist/index.d.mts CHANGED
@@ -1,16 +1,12 @@
1
1
  import { CrdtType, AbstractCrdtDoc, InferCrdtJson, AbstractCrdtDocFactory } from '@pluv/crdt';
2
2
  export { CrdtType, InferCrdtJson } from '@pluv/crdt';
3
3
  import * as _pluv_types from '@pluv/types';
4
- import { IOLike, InferIOOutput, Id, IOEventMessage, JsonObject, InferIOAuthorizeUser, InferIOAuthorize, InferIOInput, InputZodLike, InferIOAuthorizeRequired } from '@pluv/types';
4
+ import { IOLike, InferIOOutput, Id, IOEventMessage, JsonObject, InferIOAuthorizeUser, InferIOAuthorize, EventRecord, MaybePromise, InputZodLike, ProcedureLike, IORouterLike, InferIOInput, InferIOAuthorizeRequired } from '@pluv/types';
5
5
  export { BaseUser, EventMessage, EventRecord, IOEventMessage } from '@pluv/types';
6
6
  import { Subject } from 'wonka';
7
7
 
8
8
  type EventNotifierSubscriptionCallback<TIO extends IOLike, TEvent extends keyof InferIOOutput<TIO>> = (value: Id<IOEventMessage<TIO, TEvent>>) => void;
9
9
 
10
- interface AuthorizationState<TIO extends IOLike> {
11
- token: string | null;
12
- user: InferIOAuthorizeUser<InferIOAuthorize<TIO>> | null;
13
- }
14
10
  declare enum ConnectionState {
15
11
  Closed = "Closed",
16
12
  Connecting = "Connecting",
@@ -18,6 +14,24 @@ declare enum ConnectionState {
18
14
  Unavailable = "Unavailable",
19
15
  Untouched = "Untouched"
20
16
  }
17
+
18
+ interface AuthorizationState<TIO extends IOLike> {
19
+ token: string | null;
20
+ user: InferIOAuthorizeUser<InferIOAuthorize<TIO>> | null;
21
+ }
22
+ type EventResolver<TIO extends IOLike = IOLike, TInput extends JsonObject = {}, TOutput extends EventRecord<string, any> = {}, TPresence extends JsonObject = {}, TStorage extends Record<string, CrdtType<any, any>> = {}> = (data: TInput, context: EventResolverContext<TIO, TPresence, TStorage>) => MaybePromise<TOutput | void>;
23
+ interface EventResolverContext<TIO extends IOLike = IOLike, TPresence extends JsonObject = {}, TStorage extends Record<string, CrdtType<any, any>> = {}> {
24
+ doc: AbstractCrdtDoc<TStorage>;
25
+ others: readonly UserInfo<TIO, TPresence>[];
26
+ room: string;
27
+ user: UserInfo<TIO, TPresence>;
28
+ }
29
+ type MergeEventRecords<TEventRecords extends EventRecord<string, any>[], TRoot extends EventRecord<string, any> = {}> = TEventRecords extends [
30
+ infer IHead extends EventRecord<string, any>,
31
+ ...infer ITail extends EventRecord<string, any>[]
32
+ ] ? MergeEventRecords<ITail, Omit<TRoot, keyof IHead> & {
33
+ [P in keyof IHead]: TRoot extends Record<P, any> ? TRoot[P] | IHead[P] : IHead[P];
34
+ }> : Id<TRoot>;
21
35
  type UpdateMyPresenceAction<TPresence extends JsonObject> = Partial<TPresence> | ((oldPresence: TPresence | null) => Partial<TPresence>);
22
36
  interface UserInfo<TIO extends IOLike, TPresence extends JsonObject = {}> {
23
37
  connectionId: string;
@@ -37,6 +51,40 @@ interface WebSocketState<TIO extends IOLike> {
37
51
 
38
52
  type OtherNotifierSubscriptionCallback<TIO extends IOLike> = (value: Id<UserInfo<TIO>> | null) => void;
39
53
 
54
+ interface PluvProcedureConfig<TIO extends IOLike = IOLike, TInput extends JsonObject = {}, TOutput extends EventRecord<string, any> = {}, TPresence extends JsonObject = {}, TStorage extends Record<string, CrdtType<any, any>> = {}> {
55
+ broadcast?: EventResolver<TIO, TInput, TOutput, TPresence, TStorage> | null;
56
+ input?: InputZodLike<TInput>;
57
+ }
58
+ declare class PluvProcedure<TIO extends IOLike = IOLike, TInput extends JsonObject = {}, TOutput extends EventRecord<string, any> = {}, TPresence extends JsonObject = {}, TStorage extends Record<string, CrdtType<any, any>> = {}, TFilled extends "input" | "broadcast" | "" = ""> {
59
+ private _broadcast;
60
+ private _input;
61
+ get config(): ProcedureLike<TInput, TOutput>["config"];
62
+ constructor(config?: PluvProcedureConfig<TIO, TInput, TOutput, TPresence, TStorage>);
63
+ broadcast<TResult extends EventRecord<string, any> = {}>(resolver: EventResolver<TIO, TInput, TResult, TPresence, TStorage>): Omit<PluvProcedure<TIO, TInput, MergeEventRecords<[TOutput, TResult]>, TPresence, TStorage, TFilled | "input" | "broadcast">, TFilled | "input" | "broadcast">;
64
+ input<TData extends JsonObject>(input: InputZodLike<TData>): Omit<PluvProcedure<TIO, TData, {}, TPresence, TStorage, TFilled | "input">, TFilled | "input">;
65
+ private _resolver;
66
+ }
67
+
68
+ type PluvRouterEventConfig<TIO extends IOLike = IOLike, TPresence extends JsonObject = {}, TStorage extends Record<string, CrdtType<any, any>> = {}> = {
69
+ [P: string]: Pick<PluvProcedure<TIO, any, any, TPresence, TStorage>, "config">;
70
+ };
71
+ type MergedRouter<TRouters extends PluvRouter<TIO, TPresence, TStorage, any>[] = [], TIO extends IOLike = IOLike, TPresence extends JsonObject = {}, TStorage extends Record<string, CrdtType<any, any>> = {}, TRoot extends TRouters[0]["_defs"]["events"] = {}> = TRouters extends [
72
+ infer IHead extends PluvRouter<TIO, TPresence, TStorage, any>,
73
+ ...infer ITail extends PluvRouter<TIO, TPresence, TStorage, any>[]
74
+ ] ? MergedRouter<ITail, TIO, TPresence, TStorage, TRoot & IHead["_defs"]["events"]> : PluvRouter<TIO, TPresence, TStorage, TRoot>;
75
+ type MergeEvents<TClientEvents extends PluvRouterEventConfig<any, any, any>, TServerIO extends IOLike<any, any>> = TServerIO extends IOLike<infer IAuthorize, infer IServerEvents> ? IOLike<IAuthorize, {
76
+ [P in keyof TClientEvents]: TClientEvents[P] extends ProcedureLike<infer IClientInput, infer IClientOutput> ? {
77
+ [K in keyof IClientOutput]: K extends keyof IServerEvents ? IServerEvents[K] : ProcedureLike<IClientInput, Id<Pick<IClientOutput, K>>>;
78
+ }[keyof IClientOutput] : never;
79
+ } & IServerEvents> : never;
80
+ declare class PluvRouter<TIO extends IOLike = IOLike, TPresence extends JsonObject = {}, TStorage extends Record<string, CrdtType<any, any>> = {}, TEvents extends PluvRouterEventConfig<TIO, TPresence, TStorage> = {}> implements IORouterLike<TEvents> {
81
+ readonly _defs: {
82
+ events: TEvents;
83
+ };
84
+ constructor(events: TEvents);
85
+ static merge<TRouters extends PluvRouter<any, any, any, any>[]>(...routers: TRouters): MergedRouter<TRouters>;
86
+ }
87
+
40
88
  interface StateNotifierSubjects<TIO extends IOLike, TPresence extends JsonObject> {
41
89
  connection: Subject<Id<WebSocketState<TIO>>>;
42
90
  "my-presence": Subject<TPresence | null>;
@@ -47,15 +95,15 @@ interface StateNotifierSubjects<TIO extends IOLike, TPresence extends JsonObject
47
95
  type InferSubjectValue<TIO extends IOLike, TPresence extends JsonObject, TSubject extends keyof StateNotifierSubjects<TIO, TPresence>> = StateNotifierSubjects<TIO, TPresence>[TSubject] extends Subject<infer IValue> ? Id<IValue> : never;
48
96
  type SubscriptionCallback<TIO extends IOLike, TPresence extends JsonObject, TSubject extends keyof StateNotifierSubjects<TIO, TPresence>> = (value: InferSubjectValue<TIO, TPresence, TSubject>) => void;
49
97
 
50
- declare abstract class AbstractRoom<TIO extends IOLike, TPresence extends JsonObject = {}, TStorage extends Record<string, CrdtType<any, any>> = {}> {
98
+ declare abstract class AbstractRoom<TIO extends IOLike, TPresence extends JsonObject = {}, TStorage extends Record<string, CrdtType<any, any>> = {}, TEvents extends PluvRouterEventConfig<TIO, TPresence, TStorage> = {}> {
51
99
  readonly id: string;
52
100
  constructor(room: string);
53
101
  abstract storageLoaded: boolean;
54
- abstract broadcast<TEvent extends keyof InferIOInput<TIO>>(event: TEvent, data: Id<InferIOInput<TIO>[TEvent]>): void;
102
+ abstract broadcast<TEvent extends keyof InferIOInput<MergeEvents<TEvents, TIO>>>(event: TEvent, data: Id<InferIOInput<MergeEvents<TEvents, TIO>>[TEvent]>): void;
55
103
  abstract canRedo(): boolean;
56
104
  abstract canUndo(): boolean;
57
105
  abstract getDoc(): AbstractCrdtDoc<TStorage>;
58
- abstract event<TEvent extends keyof InferIOOutput<TIO>>(event: TEvent, callback: EventNotifierSubscriptionCallback<TIO, TEvent>): () => void;
106
+ abstract event<TEvent extends keyof InferIOOutput<MergeEvents<TEvents, TIO>>>(event: TEvent, callback: EventNotifierSubscriptionCallback<MergeEvents<TEvents, TIO>, TEvent>): () => void;
59
107
  abstract getConnection(): WebSocketConnection;
60
108
  abstract getMyPresence(): TPresence;
61
109
  abstract getMyself(): Id<UserInfo<TIO, TPresence>> | null;
@@ -97,48 +145,6 @@ type UsersManagerConfig<TPresence extends JsonObject = {}> = {
97
145
  presence?: InputZodLike<TPresence>;
98
146
  };
99
147
 
100
- type MockedRoomEvents<TIO extends IOLike> = Partial<{
101
- [P in keyof InferIOInput<TIO>]: (data: Id<InferIOInput<TIO>[P]>) => Partial<InferIOOutput<TIO>>;
102
- }>;
103
- type MockedRoomConfig<TIO extends IOLike, TPresence extends JsonObject = {}, TStorage extends Record<string, CrdtType<any, any>> = {}> = {
104
- events?: MockedRoomEvents<TIO>;
105
- } & Omit<CrdtManagerOptions<TStorage>, "encodedState"> & UsersManagerConfig<TPresence>;
106
- declare class MockedRoom<TIO extends IOLike, TPresence extends JsonObject = {}, TStorage extends Record<string, CrdtType<any, any>> = {}> extends AbstractRoom<TIO, TPresence, TStorage> {
107
- private _crdtManager;
108
- private _crdtNotifier;
109
- private _eventNotifier;
110
- private _events?;
111
- private _otherNotifier;
112
- private _state;
113
- private _stateNotifier;
114
- private _subscriptions;
115
- private _usersManager;
116
- constructor(room: string, options: MockedRoomConfig<TIO, TPresence, TStorage>);
117
- get storageLoaded(): boolean;
118
- broadcast<TEvent extends keyof InferIOInput<TIO>>(event: TEvent, data: Id<InferIOInput<TIO>[TEvent]>): void;
119
- canRedo: () => boolean;
120
- canUndo: () => boolean;
121
- event: <TEvent extends keyof InferIOOutput<TIO>>(event: TEvent, callback: EventNotifierSubscriptionCallback<TIO, TEvent>) => (() => void);
122
- getConnection: () => WebSocketConnection;
123
- getDoc(): AbstractCrdtDoc<TStorage>;
124
- getMyPresence: () => TPresence;
125
- getMyself: () => Id<UserInfo<TIO, TPresence>> | null;
126
- getOther: (connectionId: string) => Id<UserInfo<TIO, TPresence>> | null;
127
- getOthers: () => readonly Id<UserInfo<TIO, TPresence>>[];
128
- getStorage: <TKey extends keyof TStorage>(type: TKey) => TStorage[TKey] | null;
129
- getStorageJson(): InferCrdtJson<TStorage> | null;
130
- getStorageJson<TKey extends keyof TStorage>(type: TKey): InferCrdtJson<TStorage[TKey]> | null;
131
- other: (connectionId: string, callback: OtherNotifierSubscriptionCallback<TIO>) => (() => void);
132
- redo: () => void;
133
- storage: <TKey extends keyof TStorage>(key: TKey, fn: (value: InferCrdtJson<TStorage[TKey]>) => void) => (() => void);
134
- storageRoot: (fn: (value: { [P in keyof TStorage]: InferCrdtJson<TStorage[P]>; }) => void) => (() => void);
135
- subscribe: <TSubject extends keyof StateNotifierSubjects<TIO, TPresence>>(name: TSubject, callback: SubscriptionCallback<TIO, TPresence, TSubject>) => (() => void);
136
- transact: (fn: (storage: TStorage) => void, origin?: string) => void;
137
- undo: () => void;
138
- updateMyPresence: (presence: UpdateMyPresenceAction<TPresence>) => void;
139
- private _observeCrdt;
140
- }
141
-
142
148
  declare global {
143
149
  var process: {
144
150
  env: {
@@ -146,22 +152,26 @@ declare global {
146
152
  };
147
153
  };
148
154
  }
149
- type AuthEndpoint = string | ((room: string) => string | FetchOptions) | true;
150
- type WsEndpoint = string | ((room: string) => string);
155
+ interface EndpointParams<TMetadata extends JsonObject> {
156
+ metadata: TMetadata;
157
+ room: string;
158
+ }
159
+ type AuthEndpoint<TMetadata extends JsonObject> = string | ((params: EndpointParams<TMetadata>) => string | FetchOptions) | true;
160
+ type WsEndpoint<TMetadata extends JsonObject> = string | ((params: EndpointParams<TMetadata>) => string);
151
161
  type FetchOptions = {
152
162
  url: string;
153
163
  options?: RequestInit;
154
164
  };
155
- type RoomEndpoints<TIO extends IOLike> = {
156
- wsEndpoint?: WsEndpoint;
165
+ type RoomEndpoints<TIO extends IOLike, TMetadata extends JsonObject> = {
166
+ wsEndpoint?: WsEndpoint<TMetadata>;
157
167
  } & (InferIOAuthorizeRequired<InferIOAuthorize<TIO>> extends true ? {
158
- authEndpoint: AuthEndpoint;
168
+ authEndpoint: AuthEndpoint<TMetadata>;
159
169
  } : {
160
170
  authEndpoint?: undefined;
161
171
  });
162
- type PluvRoomAddon<TIO extends IOLike = IOLike, TPresence extends JsonObject = {}, TStorage extends Record<string, CrdtType<any, any>> = {}> = (input: PluvRoomAddonInput<TIO, TPresence, TStorage>) => Partial<PluvRoomAddonResult>;
163
- interface PluvRoomAddonInput<TIO extends IOLike = IOLike, TPresence extends JsonObject = {}, TStorage extends Record<string, CrdtType<any, any>> = {}> {
164
- room: PluvRoom<TIO, TPresence, TStorage>;
172
+ type PluvRoomAddon<TIO extends IOLike = IOLike, TMetadata extends JsonObject = {}, TPresence extends JsonObject = {}, TStorage extends Record<string, CrdtType<any, any>> = {}> = (input: PluvRoomAddonInput<TIO, TMetadata, TPresence, TStorage>) => Partial<PluvRoomAddonResult>;
173
+ interface PluvRoomAddonInput<TIO extends IOLike = IOLike, TMetadata extends JsonObject = {}, TPresence extends JsonObject = {}, TStorage extends Record<string, CrdtType<any, any>> = {}> {
174
+ room: PluvRoom<TIO, TMetadata, TPresence, TStorage>;
165
175
  }
166
176
  interface PluvRoomAddonResult {
167
177
  storage: AbstractStorageStore;
@@ -170,21 +180,27 @@ type PluvRoomDebug<TIO extends IOLike> = Id<{
170
180
  output: readonly (keyof InferIOOutput<TIO>)[];
171
181
  input: readonly (keyof InferIOInput<TIO>)[];
172
182
  }>;
173
- type PluvRoomOptions<TIO extends IOLike, TPresence extends JsonObject = {}, TStorage extends Record<string, CrdtType<any, any>> = {}> = {
174
- addons?: readonly PluvRoomAddon<TIO, TPresence, TStorage>[];
183
+ type RoomConfig<TIO extends IOLike, TMetadata extends JsonObject = {}, TPresence extends JsonObject = {}, TStorage extends Record<string, CrdtType<any, any>> = {}, TEvents extends PluvRouterEventConfig<TIO, TPresence, TStorage> = {}> = Id<{
184
+ addons?: readonly PluvRoomAddon<TIO, TMetadata, TPresence, TStorage>[];
175
185
  debug?: boolean | PluvRoomDebug<TIO>;
176
186
  onAuthorizationFail?: (error: Error) => void;
177
- } & Omit<CrdtManagerOptions<TStorage>, "encodedState"> & UsersManagerConfig<TPresence>;
178
- type RoomConfig<TIO extends IOLike, TPresence extends JsonObject = {}, TStorage extends Record<string, CrdtType<any, any>> = {}> = RoomEndpoints<TIO> & PluvRoomOptions<TIO, TPresence, TStorage>;
179
- declare class PluvRoom<TIO extends IOLike, TPresence extends JsonObject = {}, TStorage extends Record<string, CrdtType<any, any>> = {}> extends AbstractRoom<TIO, TPresence, TStorage> {
180
- readonly _endpoints: RoomEndpoints<TIO>;
187
+ router?: PluvRouter<TIO, TPresence, TStorage, TEvents>;
188
+ } & RoomEndpoints<TIO, TMetadata> & Pick<CrdtManagerOptions<TStorage>, "initialStorage"> & UsersManagerConfig<TPresence> & (keyof TMetadata extends never ? {
189
+ metadata?: undefined;
190
+ } : {
191
+ metadata: TMetadata;
192
+ })>;
193
+ declare class PluvRoom<TIO extends IOLike, TMetadata extends JsonObject = {}, TPresence extends JsonObject = {}, TStorage extends Record<string, CrdtType<any, any>> = {}, TEvents extends PluvRouterEventConfig<TIO, TPresence, TStorage> = {}> extends AbstractRoom<TIO, TPresence, TStorage> {
194
+ readonly _endpoints: RoomEndpoints<TIO, TMetadata>;
181
195
  private _crdtManager;
182
196
  private _crdtNotifier;
183
197
  private _debug;
184
198
  private _eventNotifier;
185
199
  private _intervals;
186
200
  private _listeners;
201
+ private _metadata;
187
202
  private _otherNotifier;
203
+ private _router;
188
204
  private _state;
189
205
  private _stateNotifier;
190
206
  private _storageStore;
@@ -193,15 +209,15 @@ declare class PluvRoom<TIO extends IOLike, TPresence extends JsonObject = {}, TS
193
209
  private _windowListeners;
194
210
  private _wsListeners;
195
211
  private _usersManager;
196
- constructor(room: string, options: RoomConfig<TIO, TPresence, TStorage>);
212
+ constructor(room: string, options: RoomConfig<TIO, TMetadata, TPresence, TStorage, TEvents>);
197
213
  get storageLoaded(): boolean;
198
214
  get webSocket(): WebSocket | null;
199
- broadcast: (<TEvent extends keyof InferIOInput<TIO>>(event: TEvent, data: Id<InferIOInput<TIO>[TEvent]>) => void) & { [event in keyof InferIOInput<TIO>]: (data: Id<InferIOInput<TIO>[event]>) => void; };
215
+ broadcast: (<TEvent extends keyof InferIOInput<MergeEvents<TEvents, TIO>>>(event: TEvent, data: Id<InferIOInput<MergeEvents<TEvents, TIO>>[TEvent]>) => Promise<void>) & { [event in keyof InferIOInput<TIO>]: (data: Id<InferIOInput<TIO>[event]>) => Promise<void>; };
200
216
  canRedo: () => boolean;
201
217
  canUndo: () => boolean;
202
218
  connect(): Promise<void>;
203
219
  disconnect(): Promise<void>;
204
- event: (<TEvent extends keyof InferIOOutput<TIO>>(event: TEvent, callback: EventNotifierSubscriptionCallback<TIO, TEvent>) => () => void) & { [event in keyof InferIOOutput<TIO>]: (callback: EventNotifierSubscriptionCallback<TIO, event>) => () => void; };
220
+ event: (<TEvent extends keyof InferIOOutput<MergeEvents<TEvents, TIO>>>(event: TEvent, callback: EventNotifierSubscriptionCallback<MergeEvents<TEvents, TIO>, TEvent>) => () => void) & { [event in keyof InferIOOutput<MergeEvents<TEvents, TIO>>]: (callback: EventNotifierSubscriptionCallback<MergeEvents<TEvents, TIO>, any>) => () => void; };
205
221
  getConnection: () => WebSocketConnection;
206
222
  getDoc: () => AbstractCrdtDoc<TStorage>;
207
223
  getMyPresence: () => TPresence;
@@ -270,23 +286,93 @@ declare class PluvRoom<TIO extends IOLike, TPresence extends JsonObject = {}, TS
270
286
  private _updateState;
271
287
  }
272
288
 
273
- type PluvClientOptions<TIO extends IOLike> = RoomEndpoints<TIO> & {
289
+ declare const identity: <T extends unknown>(x: T) => T;
290
+
291
+ type InferCallback<TIO extends IOLike> = (i: typeof identity) => {
292
+ io: (io: TIO) => TIO;
293
+ };
294
+ type PluvClientOptions<TIO extends IOLike, TPresence extends JsonObject, TStorage extends Record<string, CrdtType<any, any>>, TMetadata extends JsonObject> = RoomEndpoints<TIO, TMetadata> & {
274
295
  debug?: boolean;
296
+ infer: InferCallback<TIO>;
297
+ initialStorage?: AbstractCrdtDocFactory<TStorage>;
298
+ metadata?: InputZodLike<TMetadata>;
299
+ presence?: InputZodLike<TPresence>;
275
300
  };
276
- declare class PluvClient<TIO extends IOLike = IOLike> {
301
+ type CreateRoomOptions<TIO extends IOLike, TPresence extends JsonObject, TStorage extends Record<string, CrdtType<any, any>>, TMetadata extends JsonObject, TEvents extends PluvRouterEventConfig<TIO, TPresence, TStorage> = {}> = {
302
+ addons?: readonly PluvRoomAddon<TIO, TMetadata, TPresence, TStorage>[];
303
+ debug?: boolean | PluvRoomDebug<TIO>;
304
+ initialPresence?: TPresence;
305
+ initialStorage?: AbstractCrdtDocFactory<TStorage>;
306
+ onAuthorizationFail?: (error: Error) => void;
307
+ router?: PluvRouter<TIO, TPresence, TStorage, TEvents>;
308
+ } & (keyof TMetadata extends never ? {
309
+ metadata?: undefined;
310
+ } : {
311
+ metadata: TMetadata;
312
+ });
313
+ declare class PluvClient<TIO extends IOLike = IOLike, TPresence extends JsonObject = {}, TStorage extends Record<string, CrdtType<any, any>> = {}, TMetadata extends JsonObject = {}> {
277
314
  private _authEndpoint;
278
315
  private _debug;
316
+ private _initialStorage?;
317
+ private _presence?;
279
318
  private _wsEndpoint;
280
319
  private _rooms;
281
- constructor(options: PluvClientOptions<TIO>);
282
- createRoom: <TPresence extends JsonObject = {}, TStorage extends Record<string, CrdtType<any, any>> = {}>(room: string, options: PluvRoomOptions<TIO, TPresence, TStorage>) => PluvRoom<TIO, TPresence, TStorage>;
283
- enter: (room: string | PluvRoom<TIO, any, any>) => Promise<PluvRoom<TIO, JsonObject, any>>;
284
- getRoom: <TPresence extends JsonObject = {}, TStorage extends Record<string, CrdtType<any, any>> = {}>(room: string) => PluvRoom<TIO, TPresence, TStorage> | null;
285
- getRooms: () => readonly PluvRoom<TIO, JsonObject, any>[];
286
- leave: (room: string | PluvRoom<TIO, any, any>) => Promise<void>;
320
+ get procedure(): PluvProcedure<TIO, {}, {}, TPresence, TStorage>;
321
+ constructor(options: PluvClientOptions<TIO, TPresence, TStorage, TMetadata>);
322
+ createRoom: <TEvents extends PluvRouterEventConfig<TIO, TPresence, TStorage> = {}>(room: string, options: CreateRoomOptions<TIO, TPresence, TStorage, TMetadata, TEvents>) => PluvRoom<TIO, TMetadata, TPresence, TStorage>;
323
+ enter: (room: string | PluvRoom<TIO, any, any, any>) => Promise<PluvRoom<TIO, TMetadata, TPresence, TStorage, any>>;
324
+ getRoom: (room: string) => PluvRoom<TIO, TMetadata, TPresence, TStorage, any> | null;
325
+ getRooms: () => readonly PluvRoom<TIO, TMetadata, TPresence, TStorage, any>[];
326
+ leave: (room: string | PluvRoom<TIO, any, any, any>) => Promise<void>;
327
+ router<TEvents extends PluvRouterEventConfig<TIO, TPresence, TStorage> = {}>(events: TEvents): PluvRouter<TIO, TPresence, TStorage, TEvents>;
287
328
  private _logDebug;
288
329
  }
289
330
 
290
- declare const createClient: <TIO extends IOLike = IOLike<_pluv_types.IOAuthorize<any, any, any>, {}>>(options: PluvClientOptions<TIO>) => PluvClient<TIO>;
331
+ declare const createClient: <TIO extends IOLike = IOLike<_pluv_types.IOAuthorize<any, any, any>, {}>, TPresence extends JsonObject = {}, TStorage extends Record<string, CrdtType<any, any>> = {}, TMetadata extends JsonObject = {}>(options: PluvClientOptions<TIO, TPresence, TStorage, TMetadata>) => PluvClient<TIO, TPresence, TStorage, TMetadata>;
332
+
333
+ type MockedRoomEvents<TIO extends IOLike> = Partial<{
334
+ [P in keyof InferIOInput<TIO>]: (data: Id<InferIOInput<TIO>[P]>) => Partial<InferIOOutput<TIO>>;
335
+ }>;
336
+ type MockedRoomConfig<TIO extends IOLike, TPresence extends JsonObject = {}, TStorage extends Record<string, CrdtType<any, any>> = {}, TEvents extends PluvRouterEventConfig<TIO, TPresence, TStorage> = {}> = {
337
+ events?: MockedRoomEvents<MergeEvents<TEvents, TIO>>;
338
+ router?: PluvRouter<TIO, TPresence, TStorage, TEvents>;
339
+ } & Pick<CrdtManagerOptions<TStorage>, "initialStorage"> & UsersManagerConfig<TPresence>;
340
+ declare class MockedRoom<TIO extends IOLike, TPresence extends JsonObject = {}, TStorage extends Record<string, CrdtType<any, any>> = {}, TEvents extends PluvRouterEventConfig<TIO, TPresence, TStorage> = {}> extends AbstractRoom<TIO, TPresence, TStorage> {
341
+ private _crdtManager;
342
+ private _crdtNotifier;
343
+ private _eventNotifier;
344
+ private _events?;
345
+ private _otherNotifier;
346
+ private _router;
347
+ private _state;
348
+ private _stateNotifier;
349
+ private _subscriptions;
350
+ private _usersManager;
351
+ constructor(room: string, options: MockedRoomConfig<TIO, TPresence, TStorage, TEvents>);
352
+ get storageLoaded(): boolean;
353
+ broadcast: (<TEvent extends keyof InferIOInput<MergeEvents<TEvents, TIO>>>(event: TEvent, data: Id<InferIOInput<MergeEvents<TEvents, TIO>>[TEvent]>) => Promise<void>) & { [event in keyof InferIOInput<TIO>]: (data: Id<InferIOInput<TIO>[event]>) => Promise<void>; };
354
+ canRedo: () => boolean;
355
+ canUndo: () => boolean;
356
+ event: (<TEvent extends keyof InferIOOutput<MergeEvents<TEvents, TIO>>>(event: TEvent, callback: EventNotifierSubscriptionCallback<MergeEvents<TEvents, TIO>, TEvent>) => () => void) & { [event in keyof InferIOOutput<MergeEvents<TEvents, TIO>>]: (callback: EventNotifierSubscriptionCallback<MergeEvents<TEvents, TIO>, any>) => () => void; };
357
+ getConnection: () => WebSocketConnection;
358
+ getDoc(): AbstractCrdtDoc<TStorage>;
359
+ getMyPresence: () => TPresence;
360
+ getMyself: () => Id<UserInfo<TIO, TPresence>> | null;
361
+ getOther: (connectionId: string) => Id<UserInfo<TIO, TPresence>> | null;
362
+ getOthers: () => readonly Id<UserInfo<TIO, TPresence>>[];
363
+ getStorage: <TKey extends keyof TStorage>(type: TKey) => TStorage[TKey] | null;
364
+ getStorageJson(): InferCrdtJson<TStorage> | null;
365
+ getStorageJson<TKey extends keyof TStorage>(type: TKey): InferCrdtJson<TStorage[TKey]> | null;
366
+ other: (connectionId: string, callback: OtherNotifierSubscriptionCallback<TIO>) => (() => void);
367
+ redo: () => void;
368
+ storage: <TKey extends keyof TStorage>(key: TKey, fn: (value: InferCrdtJson<TStorage[TKey]>) => void) => (() => void);
369
+ storageRoot: (fn: (value: { [P in keyof TStorage]: InferCrdtJson<TStorage[P]>; }) => void) => (() => void);
370
+ subscribe: <TSubject extends keyof StateNotifierSubjects<TIO, TPresence>>(name: TSubject, callback: SubscriptionCallback<TIO, TPresence, TSubject>) => (() => void);
371
+ transact: (fn: (storage: TStorage) => void, origin?: string) => void;
372
+ undo: () => void;
373
+ updateMyPresence: (presence: UpdateMyPresenceAction<TPresence>) => void;
374
+ private _observeCrdt;
375
+ private _simulateEvent;
376
+ }
291
377
 
292
- export { AbstractRoom, AbstractStorageStore, ConnectionState, MockedRoom, type MockedRoomConfig, type MockedRoomEvents, PluvClient, type PluvClientOptions, PluvRoom, type PluvRoomAddon, type PluvRoomAddonInput, type PluvRoomAddonResult, type PluvRoomDebug, type UserInfo, type WebSocketConnection, type WebSocketState, createClient };
378
+ export { AbstractRoom, AbstractStorageStore, ConnectionState, type CreateRoomOptions, type MergeEvents, MockedRoom, type MockedRoomConfig, type MockedRoomEvents, PluvClient, type PluvClientOptions, type PluvProcedureConfig, PluvRoom, type PluvRoomAddon, type PluvRoomAddonInput, type PluvRoomAddonResult, type PluvRoomDebug, PluvRouter, type PluvRouterEventConfig, type UserInfo, type WebSocketConnection, type WebSocketState, createClient };