@pluv/client 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 +112 -32
- package/dist/index.d.ts +112 -32
- package/dist/index.js +158 -26
- package/dist/index.mjs +158 -26
- package/package.json +7 -7
- package/src/AbstractRoom.ts +6 -4
- package/src/MockedRoom.ts +115 -27
- package/src/PluvClient.ts +77 -20
- package/src/PluvProcedure.ts +81 -0
- package/src/PluvRoom.ts +82 -30
- package/src/PluvRouter.ts +70 -0
- package/src/createClient.ts +10 -4
- package/src/enums.ts +7 -0
- package/src/index.ts +5 -9
- package/src/types.ts +43 -7
- package/src/utils/identity.ts +1 -0
- package/src/utils/index.ts +1 -0
package/dist/index.d.ts
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,
|
|
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
|
|
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
|
|
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;
|
|
@@ -132,17 +180,17 @@ type PluvRoomDebug<TIO extends IOLike> = Id<{
|
|
|
132
180
|
output: readonly (keyof InferIOOutput<TIO>)[];
|
|
133
181
|
input: readonly (keyof InferIOInput<TIO>)[];
|
|
134
182
|
}>;
|
|
135
|
-
type
|
|
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<{
|
|
136
184
|
addons?: readonly PluvRoomAddon<TIO, TMetadata, TPresence, TStorage>[];
|
|
137
185
|
debug?: boolean | PluvRoomDebug<TIO>;
|
|
138
186
|
onAuthorizationFail?: (error: Error) => void;
|
|
139
|
-
|
|
187
|
+
router?: PluvRouter<TIO, TPresence, TStorage, TEvents>;
|
|
188
|
+
} & RoomEndpoints<TIO, TMetadata> & Pick<CrdtManagerOptions<TStorage>, "initialStorage"> & UsersManagerConfig<TPresence> & (keyof TMetadata extends never ? {
|
|
140
189
|
metadata?: undefined;
|
|
141
190
|
} : {
|
|
142
191
|
metadata: TMetadata;
|
|
143
|
-
})
|
|
144
|
-
|
|
145
|
-
declare class PluvRoom<TIO extends IOLike, TMetadata extends JsonObject = {}, TPresence extends JsonObject = {}, TStorage extends Record<string, CrdtType<any, any>> = {}> extends AbstractRoom<TIO, TPresence, TStorage> {
|
|
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> {
|
|
146
194
|
readonly _endpoints: RoomEndpoints<TIO, TMetadata>;
|
|
147
195
|
private _crdtManager;
|
|
148
196
|
private _crdtNotifier;
|
|
@@ -152,6 +200,7 @@ declare class PluvRoom<TIO extends IOLike, TMetadata extends JsonObject = {}, TP
|
|
|
152
200
|
private _listeners;
|
|
153
201
|
private _metadata;
|
|
154
202
|
private _otherNotifier;
|
|
203
|
+
private _router;
|
|
155
204
|
private _state;
|
|
156
205
|
private _stateNotifier;
|
|
157
206
|
private _storageStore;
|
|
@@ -160,15 +209,15 @@ declare class PluvRoom<TIO extends IOLike, TMetadata extends JsonObject = {}, TP
|
|
|
160
209
|
private _windowListeners;
|
|
161
210
|
private _wsListeners;
|
|
162
211
|
private _usersManager;
|
|
163
|
-
constructor(room: string, options: RoomConfig<TIO, TMetadata, TPresence, TStorage>);
|
|
212
|
+
constructor(room: string, options: RoomConfig<TIO, TMetadata, TPresence, TStorage, TEvents>);
|
|
164
213
|
get storageLoaded(): boolean;
|
|
165
214
|
get webSocket(): WebSocket | null;
|
|
166
|
-
broadcast: (<TEvent extends keyof InferIOInput<TIO
|
|
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>; };
|
|
167
216
|
canRedo: () => boolean;
|
|
168
217
|
canUndo: () => boolean;
|
|
169
218
|
connect(): Promise<void>;
|
|
170
219
|
disconnect(): Promise<void>;
|
|
171
|
-
event: (<TEvent extends keyof InferIOOutput<TIO
|
|
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; };
|
|
172
221
|
getConnection: () => WebSocketConnection;
|
|
173
222
|
getDoc: () => AbstractCrdtDoc<TStorage>;
|
|
174
223
|
getMyPresence: () => TPresence;
|
|
@@ -237,47 +286,77 @@ declare class PluvRoom<TIO extends IOLike, TMetadata extends JsonObject = {}, TP
|
|
|
237
286
|
private _updateState;
|
|
238
287
|
}
|
|
239
288
|
|
|
240
|
-
|
|
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> & {
|
|
241
295
|
debug?: boolean;
|
|
296
|
+
infer: InferCallback<TIO>;
|
|
297
|
+
initialStorage?: AbstractCrdtDocFactory<TStorage>;
|
|
298
|
+
metadata?: InputZodLike<TMetadata>;
|
|
299
|
+
presence?: InputZodLike<TPresence>;
|
|
242
300
|
};
|
|
243
|
-
|
|
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 = {}> {
|
|
244
314
|
private _authEndpoint;
|
|
245
315
|
private _debug;
|
|
316
|
+
private _initialStorage?;
|
|
317
|
+
private _presence?;
|
|
246
318
|
private _wsEndpoint;
|
|
247
319
|
private _rooms;
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
320
|
+
get _defs(): {
|
|
321
|
+
initialStorage: AbstractCrdtDocFactory<TStorage> | undefined;
|
|
322
|
+
};
|
|
323
|
+
get procedure(): PluvProcedure<TIO, {}, {}, TPresence, TStorage>;
|
|
324
|
+
constructor(options: PluvClientOptions<TIO, TPresence, TStorage, TMetadata>);
|
|
325
|
+
createRoom: <TEvents extends PluvRouterEventConfig<TIO, TPresence, TStorage> = {}>(room: string, options: CreateRoomOptions<TIO, TPresence, TStorage, TMetadata, TEvents>) => PluvRoom<TIO, TMetadata, TPresence, TStorage>;
|
|
326
|
+
enter: (room: string | PluvRoom<TIO, any, any, any>) => Promise<PluvRoom<TIO, TMetadata, TPresence, TStorage, any>>;
|
|
327
|
+
getRoom: (room: string) => PluvRoom<TIO, TMetadata, TPresence, TStorage, any> | null;
|
|
328
|
+
getRooms: () => readonly PluvRoom<TIO, TMetadata, TPresence, TStorage, any>[];
|
|
253
329
|
leave: (room: string | PluvRoom<TIO, any, any, any>) => Promise<void>;
|
|
330
|
+
router<TEvents extends PluvRouterEventConfig<TIO, TPresence, TStorage> = {}>(events: TEvents): PluvRouter<TIO, TPresence, TStorage, TEvents>;
|
|
254
331
|
private _logDebug;
|
|
255
332
|
}
|
|
256
333
|
|
|
257
|
-
declare const createClient: <TIO extends IOLike = IOLike<_pluv_types.IOAuthorize<any, any, any>, {}>, TMetadata extends JsonObject = {}>(options: PluvClientOptions<TIO, TMetadata>) => PluvClient<TIO, TMetadata>;
|
|
334
|
+
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>;
|
|
258
335
|
|
|
259
336
|
type MockedRoomEvents<TIO extends IOLike> = Partial<{
|
|
260
337
|
[P in keyof InferIOInput<TIO>]: (data: Id<InferIOInput<TIO>[P]>) => Partial<InferIOOutput<TIO>>;
|
|
261
338
|
}>;
|
|
262
|
-
type MockedRoomConfig<TIO extends IOLike, TPresence extends JsonObject = {}, TStorage extends Record<string, CrdtType<any, any>> = {}> = {
|
|
263
|
-
events?: MockedRoomEvents<TIO
|
|
264
|
-
|
|
265
|
-
|
|
339
|
+
type MockedRoomConfig<TIO extends IOLike, TPresence extends JsonObject = {}, TStorage extends Record<string, CrdtType<any, any>> = {}, TEvents extends PluvRouterEventConfig<TIO, TPresence, TStorage> = {}> = {
|
|
340
|
+
events?: MockedRoomEvents<MergeEvents<TEvents, TIO>>;
|
|
341
|
+
router?: PluvRouter<TIO, TPresence, TStorage, TEvents>;
|
|
342
|
+
} & Pick<CrdtManagerOptions<TStorage>, "initialStorage"> & UsersManagerConfig<TPresence>;
|
|
343
|
+
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> {
|
|
266
344
|
private _crdtManager;
|
|
267
345
|
private _crdtNotifier;
|
|
268
346
|
private _eventNotifier;
|
|
269
347
|
private _events?;
|
|
270
348
|
private _otherNotifier;
|
|
349
|
+
private _router;
|
|
271
350
|
private _state;
|
|
272
351
|
private _stateNotifier;
|
|
273
352
|
private _subscriptions;
|
|
274
353
|
private _usersManager;
|
|
275
|
-
constructor(room: string, options: MockedRoomConfig<TIO, TPresence, TStorage>);
|
|
354
|
+
constructor(room: string, options: MockedRoomConfig<TIO, TPresence, TStorage, TEvents>);
|
|
276
355
|
get storageLoaded(): boolean;
|
|
277
|
-
broadcast<TEvent extends keyof InferIOInput<TIO
|
|
356
|
+
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>; };
|
|
278
357
|
canRedo: () => boolean;
|
|
279
358
|
canUndo: () => boolean;
|
|
280
|
-
event: <TEvent extends keyof InferIOOutput<TIO
|
|
359
|
+
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; };
|
|
281
360
|
getConnection: () => WebSocketConnection;
|
|
282
361
|
getDoc(): AbstractCrdtDoc<TStorage>;
|
|
283
362
|
getMyPresence: () => TPresence;
|
|
@@ -296,6 +375,7 @@ declare class MockedRoom<TIO extends IOLike, TPresence extends JsonObject = {},
|
|
|
296
375
|
undo: () => void;
|
|
297
376
|
updateMyPresence: (presence: UpdateMyPresenceAction<TPresence>) => void;
|
|
298
377
|
private _observeCrdt;
|
|
378
|
+
private _simulateEvent;
|
|
299
379
|
}
|
|
300
380
|
|
|
301
|
-
export { AbstractRoom, AbstractStorageStore, ConnectionState, MockedRoom, type MockedRoomConfig, type MockedRoomEvents, PluvClient, type PluvClientOptions, PluvRoom, type PluvRoomAddon, type PluvRoomAddonInput, type PluvRoomAddonResult, type PluvRoomDebug, type
|
|
381
|
+
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 };
|
package/dist/index.js
CHANGED
|
@@ -81,6 +81,41 @@ var AbstractStorageStore = class {
|
|
|
81
81
|
}
|
|
82
82
|
};
|
|
83
83
|
|
|
84
|
+
// src/PluvProcedure.ts
|
|
85
|
+
var PluvProcedure = class _PluvProcedure {
|
|
86
|
+
constructor(config = {}) {
|
|
87
|
+
this._broadcast = null;
|
|
88
|
+
this._input = null;
|
|
89
|
+
const { broadcast, input } = config;
|
|
90
|
+
this._broadcast = broadcast != null ? broadcast : null;
|
|
91
|
+
this._input = input != null ? input : null;
|
|
92
|
+
}
|
|
93
|
+
get config() {
|
|
94
|
+
var _a, _b, _c;
|
|
95
|
+
return {
|
|
96
|
+
broadcast: (_b = (_a = this._broadcast) == null ? void 0 : _a.bind(this)) != null ? _b : null,
|
|
97
|
+
input: (_c = this._input) != null ? _c : null,
|
|
98
|
+
resolver: this._resolver()
|
|
99
|
+
};
|
|
100
|
+
}
|
|
101
|
+
broadcast(resolver) {
|
|
102
|
+
const { broadcast } = this.config;
|
|
103
|
+
if (!!broadcast) throw new Error("Broadcast was already defined for this procedure");
|
|
104
|
+
return new _PluvProcedure(__spreadProps(__spreadValues({}, this.config), {
|
|
105
|
+
broadcast: resolver
|
|
106
|
+
}));
|
|
107
|
+
}
|
|
108
|
+
input(input) {
|
|
109
|
+
return new _PluvProcedure({ input });
|
|
110
|
+
}
|
|
111
|
+
_resolver() {
|
|
112
|
+
return (data, context) => {
|
|
113
|
+
var _a;
|
|
114
|
+
return (_a = this._broadcast) == null ? void 0 : _a.call(this, data, context);
|
|
115
|
+
};
|
|
116
|
+
}
|
|
117
|
+
};
|
|
118
|
+
|
|
84
119
|
// src/CrdtManager.ts
|
|
85
120
|
var import_crdt = require("@pluv/crdt");
|
|
86
121
|
var CrdtManager = class {
|
|
@@ -208,6 +243,21 @@ var OtherNotifier = class {
|
|
|
208
243
|
}
|
|
209
244
|
};
|
|
210
245
|
|
|
246
|
+
// src/PluvRouter.ts
|
|
247
|
+
var PluvRouter = class _PluvRouter {
|
|
248
|
+
constructor(events) {
|
|
249
|
+
this._defs = { events: {} };
|
|
250
|
+
this._defs = { events };
|
|
251
|
+
}
|
|
252
|
+
static merge(...routers) {
|
|
253
|
+
const events = Object.assign(/* @__PURE__ */ Object.create(null), ...routers.map((router) => router._defs.events));
|
|
254
|
+
if (Object.keys(events).some((key) => key.startsWith("$"))) {
|
|
255
|
+
throw new Error('Procedures may not start with "$"');
|
|
256
|
+
}
|
|
257
|
+
return new _PluvRouter(events);
|
|
258
|
+
}
|
|
259
|
+
};
|
|
260
|
+
|
|
211
261
|
// src/StateNotifier.ts
|
|
212
262
|
var import_wonka4 = require("wonka");
|
|
213
263
|
var StateNotifier = class {
|
|
@@ -346,7 +396,7 @@ var UsersManager = class {
|
|
|
346
396
|
}
|
|
347
397
|
};
|
|
348
398
|
|
|
349
|
-
// src/
|
|
399
|
+
// src/enums.ts
|
|
350
400
|
var ConnectionState = /* @__PURE__ */ ((ConnectionState2) => {
|
|
351
401
|
ConnectionState2["Closed"] = "Closed";
|
|
352
402
|
ConnectionState2["Connecting"] = "Connecting";
|
|
@@ -396,6 +446,7 @@ var PluvRoom = class extends AbstractRoom {
|
|
|
396
446
|
metadata,
|
|
397
447
|
onAuthorizationFail,
|
|
398
448
|
presence,
|
|
449
|
+
router,
|
|
399
450
|
wsEndpoint
|
|
400
451
|
} = options;
|
|
401
452
|
super(room);
|
|
@@ -429,17 +480,37 @@ var PluvRoom = class extends AbstractRoom {
|
|
|
429
480
|
this._windowListeners = null;
|
|
430
481
|
this._wsListeners = null;
|
|
431
482
|
this.broadcast = new Proxy(
|
|
432
|
-
(event, data) => {
|
|
483
|
+
(event, data) => __async(this, null, function* () {
|
|
433
484
|
if (!this._state.webSocket) return;
|
|
434
485
|
if (this._state.connection.state !== "Open" /* Open */) return;
|
|
435
486
|
const type = event.toString();
|
|
436
|
-
this.
|
|
437
|
-
|
|
487
|
+
const procedure = this._router._defs.events[type];
|
|
488
|
+
if (!(procedure == null ? void 0 : procedure.config.broadcast)) {
|
|
489
|
+
this._sendMessage({ data, type });
|
|
490
|
+
return;
|
|
491
|
+
}
|
|
492
|
+
const myself = this._usersManager.myself;
|
|
493
|
+
if (!myself) return;
|
|
494
|
+
const parsed = procedure.config.input ? procedure.config.input.parse(data) : data;
|
|
495
|
+
const context = {
|
|
496
|
+
doc: this._crdtManager.doc,
|
|
497
|
+
others: this._usersManager.getOthers(),
|
|
498
|
+
room: this.id,
|
|
499
|
+
user: myself
|
|
500
|
+
};
|
|
501
|
+
const output = yield procedure.config.broadcast(
|
|
502
|
+
parsed,
|
|
503
|
+
context
|
|
504
|
+
);
|
|
505
|
+
Object.entries(output).forEach(([_type, _data]) => {
|
|
506
|
+
this._sendMessage({ data: _data, type: _type });
|
|
507
|
+
});
|
|
508
|
+
}),
|
|
438
509
|
{
|
|
439
510
|
get(fn, prop) {
|
|
440
|
-
return (data) => {
|
|
441
|
-
return fn(prop, data);
|
|
442
|
-
};
|
|
511
|
+
return (data) => __async(this, null, function* () {
|
|
512
|
+
return yield fn(prop, data);
|
|
513
|
+
});
|
|
443
514
|
}
|
|
444
515
|
}
|
|
445
516
|
);
|
|
@@ -514,7 +585,10 @@ var PluvRoom = class extends AbstractRoom {
|
|
|
514
585
|
const myself = (_a = this._usersManager.myself) != null ? _a : null;
|
|
515
586
|
this._stateNotifier.subjects["my-presence"].next(myPresence);
|
|
516
587
|
!!myself && this._stateNotifier.subjects["myself"].next(myself);
|
|
517
|
-
this.broadcast(
|
|
588
|
+
this.broadcast(
|
|
589
|
+
"$UPDATE_PRESENCE",
|
|
590
|
+
{ presence: newPresence }
|
|
591
|
+
);
|
|
518
592
|
};
|
|
519
593
|
this._flattenStorageStore = debounce(
|
|
520
594
|
() => __async(this, null, function* () {
|
|
@@ -546,6 +620,7 @@ var PluvRoom = class extends AbstractRoom {
|
|
|
546
620
|
onAuthorizationFail == null ? void 0 : onAuthorizationFail(error);
|
|
547
621
|
}
|
|
548
622
|
};
|
|
623
|
+
this._router = router != null ? router : new PluvRouter({});
|
|
549
624
|
this._usersManager = new UsersManager({ initialPresence, presence });
|
|
550
625
|
this._crdtManager = new CrdtManager({ initialStorage });
|
|
551
626
|
}
|
|
@@ -1114,9 +1189,11 @@ var PluvClient = class {
|
|
|
1114
1189
|
authEndpoint: this._authEndpoint,
|
|
1115
1190
|
debug: options.debug,
|
|
1116
1191
|
initialPresence: options.initialPresence,
|
|
1117
|
-
initialStorage:
|
|
1192
|
+
initialStorage: this._initialStorage,
|
|
1118
1193
|
metadata: options.metadata,
|
|
1119
1194
|
onAuthorizationFail: options.onAuthorizationFail,
|
|
1195
|
+
presence: this._presence,
|
|
1196
|
+
router: options.router,
|
|
1120
1197
|
wsEndpoint: this._wsEndpoint
|
|
1121
1198
|
});
|
|
1122
1199
|
this._rooms.set(room, newRoom);
|
|
@@ -1145,11 +1222,24 @@ var PluvClient = class {
|
|
|
1145
1222
|
this._rooms.delete(toLeave.id);
|
|
1146
1223
|
this._logDebug(`Left and deleted room: ${room}`);
|
|
1147
1224
|
});
|
|
1148
|
-
const { authEndpoint, debug = false, wsEndpoint } = options;
|
|
1225
|
+
const { authEndpoint, debug = false, initialStorage, presence, wsEndpoint } = options;
|
|
1149
1226
|
this._authEndpoint = authEndpoint;
|
|
1150
1227
|
this._debug = debug;
|
|
1228
|
+
this._initialStorage = initialStorage;
|
|
1229
|
+
this._presence = presence;
|
|
1151
1230
|
this._wsEndpoint = wsEndpoint;
|
|
1152
1231
|
}
|
|
1232
|
+
get _defs() {
|
|
1233
|
+
return {
|
|
1234
|
+
initialStorage: this._initialStorage
|
|
1235
|
+
};
|
|
1236
|
+
}
|
|
1237
|
+
get procedure() {
|
|
1238
|
+
return new PluvProcedure();
|
|
1239
|
+
}
|
|
1240
|
+
router(events) {
|
|
1241
|
+
return new PluvRouter(events);
|
|
1242
|
+
}
|
|
1153
1243
|
_logDebug(...data) {
|
|
1154
1244
|
var _a;
|
|
1155
1245
|
if (((_a = process == null ? void 0 : process.env) == null ? void 0 : _a.NODE_ENV) === "production") return;
|
|
@@ -1165,7 +1255,7 @@ var createClient = (options) => {
|
|
|
1165
1255
|
// src/MockedRoom.ts
|
|
1166
1256
|
var MockedRoom = class extends AbstractRoom {
|
|
1167
1257
|
constructor(room, options) {
|
|
1168
|
-
const { events, initialPresence, initialStorage, presence } = options;
|
|
1258
|
+
const { events, initialPresence, initialStorage, presence, router } = options;
|
|
1169
1259
|
super(room);
|
|
1170
1260
|
this._crdtNotifier = new CrdtNotifier();
|
|
1171
1261
|
this._eventNotifier = new EventNotifier();
|
|
@@ -1186,15 +1276,55 @@ var MockedRoom = class extends AbstractRoom {
|
|
|
1186
1276
|
this._subscriptions = {
|
|
1187
1277
|
observeCrdt: null
|
|
1188
1278
|
};
|
|
1279
|
+
this.broadcast = new Proxy(
|
|
1280
|
+
(event, data) => __async(this, null, function* () {
|
|
1281
|
+
if (!this._state.webSocket) return;
|
|
1282
|
+
if (this._state.connection.state !== "Open" /* Open */) return;
|
|
1283
|
+
const type = event.toString();
|
|
1284
|
+
const procedure = this._router._defs.events[type];
|
|
1285
|
+
if (!(procedure == null ? void 0 : procedure.config.broadcast)) {
|
|
1286
|
+
this._simulateEvent(type, data);
|
|
1287
|
+
return;
|
|
1288
|
+
}
|
|
1289
|
+
const myself = this._usersManager.myself;
|
|
1290
|
+
if (!myself) return;
|
|
1291
|
+
const parsed = procedure.config.input ? procedure.config.input.parse(data) : data;
|
|
1292
|
+
const context = {
|
|
1293
|
+
doc: this._crdtManager.doc,
|
|
1294
|
+
others: this._usersManager.getOthers(),
|
|
1295
|
+
room: this.id,
|
|
1296
|
+
user: myself
|
|
1297
|
+
};
|
|
1298
|
+
const output = yield procedure.config.broadcast(
|
|
1299
|
+
parsed,
|
|
1300
|
+
context
|
|
1301
|
+
);
|
|
1302
|
+
Object.entries(output).forEach(([_type, _data]) => {
|
|
1303
|
+
this._simulateEvent(_type, _data);
|
|
1304
|
+
});
|
|
1305
|
+
}),
|
|
1306
|
+
{
|
|
1307
|
+
get(fn, prop) {
|
|
1308
|
+
return (data) => __async(this, null, function* () {
|
|
1309
|
+
return yield fn(prop, data);
|
|
1310
|
+
});
|
|
1311
|
+
}
|
|
1312
|
+
}
|
|
1313
|
+
);
|
|
1189
1314
|
this.canRedo = () => {
|
|
1190
1315
|
return !!this._crdtManager.doc.canRedo();
|
|
1191
1316
|
};
|
|
1192
1317
|
this.canUndo = () => {
|
|
1193
1318
|
return !!this._crdtManager.doc.canUndo();
|
|
1194
1319
|
};
|
|
1195
|
-
this.event = (
|
|
1196
|
-
|
|
1197
|
-
|
|
1320
|
+
this.event = new Proxy(
|
|
1321
|
+
(event, callback) => this._eventNotifier.subscribe(event, callback),
|
|
1322
|
+
{
|
|
1323
|
+
get(fn, prop) {
|
|
1324
|
+
return (callback) => fn(prop, callback);
|
|
1325
|
+
}
|
|
1326
|
+
}
|
|
1327
|
+
);
|
|
1198
1328
|
this.getConnection = () => {
|
|
1199
1329
|
return Object.freeze(JSON.parse(JSON.stringify(this._state.connection)));
|
|
1200
1330
|
};
|
|
@@ -1253,6 +1383,7 @@ var MockedRoom = class extends AbstractRoom {
|
|
|
1253
1383
|
!!myself && this._stateNotifier.subjects["myself"].next(myself);
|
|
1254
1384
|
};
|
|
1255
1385
|
this._events = events;
|
|
1386
|
+
this._router = router != null ? router : new PluvRouter({});
|
|
1256
1387
|
this._usersManager = new UsersManager({
|
|
1257
1388
|
initialPresence,
|
|
1258
1389
|
presence
|
|
@@ -1265,18 +1396,6 @@ var MockedRoom = class extends AbstractRoom {
|
|
|
1265
1396
|
get storageLoaded() {
|
|
1266
1397
|
return true;
|
|
1267
1398
|
}
|
|
1268
|
-
broadcast(event, data) {
|
|
1269
|
-
if (!this._events) return;
|
|
1270
|
-
const resolver = this._events[event];
|
|
1271
|
-
if (!resolver) return;
|
|
1272
|
-
const result = resolver(data);
|
|
1273
|
-
Object.keys(result).forEach((type) => {
|
|
1274
|
-
const _type = type.toString();
|
|
1275
|
-
const data2 = result[_type];
|
|
1276
|
-
if (!data2) return;
|
|
1277
|
-
this._eventNotifier.subject(_type).next(data2);
|
|
1278
|
-
});
|
|
1279
|
-
}
|
|
1280
1399
|
getDoc() {
|
|
1281
1400
|
return this._crdtManager.doc;
|
|
1282
1401
|
}
|
|
@@ -1308,6 +1427,19 @@ var MockedRoom = class extends AbstractRoom {
|
|
|
1308
1427
|
});
|
|
1309
1428
|
this._subscriptions.observeCrdt = unsubscribe;
|
|
1310
1429
|
}
|
|
1430
|
+
_simulateEvent(event, data) {
|
|
1431
|
+
if (!this._events) return;
|
|
1432
|
+
const type = event.toString();
|
|
1433
|
+
const resolver = this._events[type];
|
|
1434
|
+
if (!resolver) return;
|
|
1435
|
+
const result = resolver(data);
|
|
1436
|
+
Object.keys(result).forEach((type2) => {
|
|
1437
|
+
const _type = type2.toString();
|
|
1438
|
+
const data2 = result[_type];
|
|
1439
|
+
if (!data2) return;
|
|
1440
|
+
this._eventNotifier.subject(_type).next(data2);
|
|
1441
|
+
});
|
|
1442
|
+
}
|
|
1311
1443
|
};
|
|
1312
1444
|
// Annotate the CommonJS export names for ESM import in node:
|
|
1313
1445
|
0 && (module.exports = {
|