@pluv/io 0.3.8 → 0.4.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 +7 -7
- package/CHANGELOG.md +25 -0
- package/dist/index.d.ts +29 -24
- package/dist/index.js +200 -179
- package/dist/index.mjs +200 -179
- package/package.json +9 -9
- package/src/IORoom.ts +243 -199
- package/src/PluvIO.ts +169 -59
- package/src/types.ts +38 -7
package/src/PluvIO.ts
CHANGED
|
@@ -1,22 +1,24 @@
|
|
|
1
1
|
import type {
|
|
2
|
+
BaseIOAuthorize,
|
|
2
3
|
EventRecord,
|
|
4
|
+
IOAuthorize,
|
|
5
|
+
IOLike,
|
|
3
6
|
InferIOAuthorize,
|
|
4
7
|
InferIOAuthorizeUser,
|
|
5
8
|
InferIOInput,
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
+
InferIOOutputBroadcast,
|
|
10
|
+
InferIOOutputSelf,
|
|
11
|
+
InferIOOutputSync,
|
|
9
12
|
JsonObject,
|
|
10
|
-
Spread,
|
|
11
|
-
BaseIOAuthorize,
|
|
12
|
-
MaybePromise,
|
|
13
13
|
Maybe,
|
|
14
|
+
MaybePromise,
|
|
15
|
+
Spread,
|
|
14
16
|
} from "@pluv/types";
|
|
15
17
|
import colors from "kleur";
|
|
16
18
|
import type { AbstractPlatform } from "./AbstractPlatform";
|
|
19
|
+
import { IORoom } from "./IORoom";
|
|
17
20
|
import type { JWTEncodeParams } from "./authorize";
|
|
18
21
|
import { authorize } from "./authorize";
|
|
19
|
-
import { IORoom } from "./IORoom";
|
|
20
22
|
import type { EventConfig, InferEventConfig } from "./types";
|
|
21
23
|
|
|
22
24
|
export type InferIOContext<TIO extends PluvIO<any, any, any, any, any>> =
|
|
@@ -50,12 +52,20 @@ export type PluvIOConfig<
|
|
|
50
52
|
TAuthorize extends IOAuthorize<any, any> | null = null,
|
|
51
53
|
TContext extends JsonObject = {},
|
|
52
54
|
TInput extends EventRecord<string, any> = {},
|
|
53
|
-
|
|
55
|
+
TOutputBroadcast extends EventRecord<string, any> = {},
|
|
56
|
+
TOutputSelf extends EventRecord<string, any> = {},
|
|
57
|
+
TOutputSync extends EventRecord<string, any> = {}
|
|
54
58
|
> = Partial<PluvIOListeners> & {
|
|
55
59
|
authorize?: TAuthorize;
|
|
56
60
|
context?: TContext;
|
|
57
61
|
debug?: boolean;
|
|
58
|
-
events?: InferEventConfig<
|
|
62
|
+
events?: InferEventConfig<
|
|
63
|
+
TContext,
|
|
64
|
+
TInput,
|
|
65
|
+
TOutputBroadcast,
|
|
66
|
+
TOutputSelf,
|
|
67
|
+
TOutputSync
|
|
68
|
+
>;
|
|
59
69
|
initialStorage?: (room: string) => MaybePromise<Maybe<string>>;
|
|
60
70
|
platform: TPlatform;
|
|
61
71
|
};
|
|
@@ -69,8 +79,11 @@ export class PluvIO<
|
|
|
69
79
|
TAuthorize extends IOAuthorize<any, any> = BaseIOAuthorize,
|
|
70
80
|
TContext extends JsonObject = {},
|
|
71
81
|
TInput extends EventRecord<string, any> = {},
|
|
72
|
-
|
|
73
|
-
|
|
82
|
+
TOutputBroadcast extends EventRecord<string, any> = {},
|
|
83
|
+
TOutputSelf extends EventRecord<string, any> = {},
|
|
84
|
+
TOutputSync extends EventRecord<string, any> = {}
|
|
85
|
+
> implements
|
|
86
|
+
IOLike<TAuthorize, TInput, TOutputBroadcast, TOutputSelf, TOutputSync>
|
|
74
87
|
{
|
|
75
88
|
private _context: TContext = {} as TContext;
|
|
76
89
|
private _initialStorage:
|
|
@@ -79,50 +92,112 @@ export class PluvIO<
|
|
|
79
92
|
private _listeners: PluvIOListeners;
|
|
80
93
|
private _rooms = new Map<
|
|
81
94
|
string,
|
|
82
|
-
IORoom<
|
|
95
|
+
IORoom<
|
|
96
|
+
TPlatform,
|
|
97
|
+
TAuthorize,
|
|
98
|
+
TContext,
|
|
99
|
+
TInput,
|
|
100
|
+
TOutputBroadcast,
|
|
101
|
+
TOutputSelf,
|
|
102
|
+
TOutputSync
|
|
103
|
+
>
|
|
83
104
|
>();
|
|
84
105
|
|
|
85
106
|
readonly _authorize: TAuthorize | null = null;
|
|
86
107
|
readonly _debug: boolean;
|
|
87
|
-
readonly _events: InferEventConfig<
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
108
|
+
readonly _events: InferEventConfig<
|
|
109
|
+
TContext,
|
|
110
|
+
TInput,
|
|
111
|
+
TOutputBroadcast,
|
|
112
|
+
TOutputSelf,
|
|
113
|
+
TOutputSync
|
|
114
|
+
> = {
|
|
115
|
+
$GET_OTHERS: {
|
|
116
|
+
resolver: {
|
|
117
|
+
sync: (data, { room, session, sessions }) => {
|
|
118
|
+
const others = Array.from(sessions.entries())
|
|
119
|
+
.filter(([, wsSession]) => wsSession.id !== session?.id)
|
|
120
|
+
.reduce<{
|
|
121
|
+
[connectionId: string]: {
|
|
122
|
+
connectionId: string;
|
|
123
|
+
room: string | null;
|
|
124
|
+
user: InferIOAuthorizeUser<TAuthorize>;
|
|
125
|
+
};
|
|
126
|
+
}>(
|
|
127
|
+
(acc, [connectionId, { presence, user }]) => ({
|
|
128
|
+
...acc,
|
|
129
|
+
[connectionId]: {
|
|
130
|
+
connectionId,
|
|
131
|
+
presence,
|
|
132
|
+
room,
|
|
133
|
+
user: user as InferIOAuthorizeUser<TAuthorize>,
|
|
134
|
+
},
|
|
135
|
+
}),
|
|
136
|
+
{}
|
|
137
|
+
);
|
|
138
|
+
|
|
139
|
+
return { $OTHERS_RECEIVED: { others } };
|
|
140
|
+
},
|
|
141
|
+
},
|
|
142
|
+
},
|
|
143
|
+
$INITIALIZE_SESSION: {
|
|
144
|
+
resolver: {
|
|
145
|
+
broadcast: ({ presence }, { session }) => {
|
|
146
|
+
if (!session) return {};
|
|
147
|
+
|
|
148
|
+
session.presence = presence;
|
|
149
|
+
|
|
150
|
+
return {
|
|
151
|
+
$USER_JOINED: {
|
|
152
|
+
connectionId: session.id,
|
|
153
|
+
user: session.user,
|
|
154
|
+
presence,
|
|
155
|
+
},
|
|
156
|
+
};
|
|
157
|
+
},
|
|
158
|
+
self: async ({ update }, { doc, room }) => {
|
|
159
|
+
const oldState =
|
|
160
|
+
await this._platform.persistance.getStorageState(room);
|
|
161
|
+
|
|
162
|
+
const updates: readonly Maybe<string>[] = [
|
|
163
|
+
oldState ? null : await this._initialStorage?.(room),
|
|
164
|
+
update,
|
|
165
|
+
];
|
|
166
|
+
|
|
167
|
+
if (updates.some((_update) => !!_update)) {
|
|
168
|
+
const state = updates
|
|
169
|
+
.reduce((_doc, _up) => _doc.applyUpdate(_up), doc)
|
|
170
|
+
.encodeStateAsUpdate();
|
|
171
|
+
|
|
172
|
+
await this._platform.persistance.setStorageState(
|
|
173
|
+
room,
|
|
174
|
+
state
|
|
175
|
+
);
|
|
91
176
|
|
|
92
|
-
|
|
177
|
+
this._listeners.onStorageUpdated(room, state);
|
|
178
|
+
}
|
|
93
179
|
|
|
94
|
-
|
|
180
|
+
const state =
|
|
181
|
+
(await this._platform.persistance.getStorageState(
|
|
182
|
+
room
|
|
183
|
+
)) ?? doc.encodeStateAsUpdate();
|
|
95
184
|
|
|
96
|
-
|
|
185
|
+
return { $STORAGE_RECEIVED: { state } };
|
|
186
|
+
},
|
|
97
187
|
},
|
|
98
|
-
options: { type: "self" },
|
|
99
188
|
},
|
|
100
|
-
$
|
|
101
|
-
resolver:
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
user: InferIOAuthorizeUser<TAuthorize>;
|
|
109
|
-
};
|
|
110
|
-
}>(
|
|
111
|
-
(acc, [connectionId, { presence, user }]) => ({
|
|
112
|
-
...acc,
|
|
113
|
-
[connectionId]: {
|
|
114
|
-
connectionId,
|
|
115
|
-
presence,
|
|
116
|
-
room,
|
|
117
|
-
user: user as InferIOAuthorizeUser<TAuthorize>,
|
|
118
|
-
},
|
|
119
|
-
}),
|
|
120
|
-
{}
|
|
121
|
-
);
|
|
189
|
+
$PING: {
|
|
190
|
+
resolver: {
|
|
191
|
+
self: (data, { session }) => {
|
|
192
|
+
if (!session) return {};
|
|
193
|
+
|
|
194
|
+
const currentTime = new Date().getTime();
|
|
195
|
+
|
|
196
|
+
session.timers.ping = currentTime;
|
|
122
197
|
|
|
123
|
-
|
|
198
|
+
return { $PONG: {} };
|
|
199
|
+
},
|
|
124
200
|
},
|
|
125
|
-
options: { type: "sync" },
|
|
126
201
|
},
|
|
127
202
|
$UPDATE_PRESENCE: {
|
|
128
203
|
resolver: ({ presence }, { session }) => {
|
|
@@ -158,11 +233,25 @@ export class PluvIO<
|
|
|
158
233
|
return { $STORAGE_UPDATED: { state } };
|
|
159
234
|
},
|
|
160
235
|
},
|
|
161
|
-
} as InferEventConfig<
|
|
236
|
+
} as InferEventConfig<
|
|
237
|
+
TContext,
|
|
238
|
+
TInput,
|
|
239
|
+
TOutputBroadcast,
|
|
240
|
+
TOutputSelf,
|
|
241
|
+
TOutputSync
|
|
242
|
+
>;
|
|
162
243
|
readonly _platform: TPlatform;
|
|
163
244
|
|
|
164
245
|
constructor(
|
|
165
|
-
options: PluvIOConfig<
|
|
246
|
+
options: PluvIOConfig<
|
|
247
|
+
TPlatform,
|
|
248
|
+
TAuthorize,
|
|
249
|
+
TContext,
|
|
250
|
+
TInput,
|
|
251
|
+
TOutputBroadcast,
|
|
252
|
+
TOutputSelf,
|
|
253
|
+
TOutputSync
|
|
254
|
+
>
|
|
166
255
|
) {
|
|
167
256
|
const {
|
|
168
257
|
authorize,
|
|
@@ -211,16 +300,26 @@ export class PluvIO<
|
|
|
211
300
|
public event<
|
|
212
301
|
TEvent extends string,
|
|
213
302
|
TData extends JsonObject = {},
|
|
214
|
-
|
|
303
|
+
TResultBroadcast extends EventRecord<string, any> = {},
|
|
304
|
+
TResultSelf extends EventRecord<string, any> = {},
|
|
305
|
+
TResultSync extends EventRecord<string, any> = {}
|
|
215
306
|
>(
|
|
216
307
|
event: TEvent,
|
|
217
|
-
config: EventConfig<
|
|
308
|
+
config: EventConfig<
|
|
309
|
+
TContext,
|
|
310
|
+
TData,
|
|
311
|
+
TResultBroadcast,
|
|
312
|
+
TResultSelf,
|
|
313
|
+
TResultSync
|
|
314
|
+
>
|
|
218
315
|
): PluvIO<
|
|
219
316
|
TPlatform,
|
|
220
317
|
TAuthorize,
|
|
221
318
|
TContext,
|
|
222
319
|
Spread<[TInput, EventRecord<TEvent, TData>]>,
|
|
223
|
-
Spread<[
|
|
320
|
+
Spread<[TOutputBroadcast, TResultBroadcast]>,
|
|
321
|
+
Spread<[TOutputSelf, TResultSelf]>,
|
|
322
|
+
Spread<[TOutputSync, TResultSync]>
|
|
224
323
|
> {
|
|
225
324
|
if (event.startsWith("$")) {
|
|
226
325
|
throw new Error('Event name must not start with "$".');
|
|
@@ -231,7 +330,11 @@ export class PluvIO<
|
|
|
231
330
|
} as InferEventConfig<
|
|
232
331
|
TContext,
|
|
233
332
|
EventRecord<TEvent, TData>,
|
|
234
|
-
|
|
333
|
+
TResultBroadcast extends EventRecord<string, any>
|
|
334
|
+
? TResultBroadcast
|
|
335
|
+
: {},
|
|
336
|
+
TResultSelf extends EventRecord<string, any> ? TResultSelf : {},
|
|
337
|
+
TResultSync extends EventRecord<string, any> ? TResultSync : {}
|
|
235
338
|
>;
|
|
236
339
|
|
|
237
340
|
/**
|
|
@@ -259,7 +362,15 @@ export class PluvIO<
|
|
|
259
362
|
public getRoom(
|
|
260
363
|
room: string,
|
|
261
364
|
options: GetRoomOptions = {}
|
|
262
|
-
): IORoom<
|
|
365
|
+
): IORoom<
|
|
366
|
+
TPlatform,
|
|
367
|
+
TAuthorize,
|
|
368
|
+
TContext,
|
|
369
|
+
TInput,
|
|
370
|
+
TOutputBroadcast,
|
|
371
|
+
TOutputSelf,
|
|
372
|
+
TOutputSync
|
|
373
|
+
> {
|
|
263
374
|
const { debug } = options;
|
|
264
375
|
|
|
265
376
|
this._purgeEmptyRooms();
|
|
@@ -278,7 +389,9 @@ export class PluvIO<
|
|
|
278
389
|
TAuthorize,
|
|
279
390
|
TContext,
|
|
280
391
|
TInput,
|
|
281
|
-
|
|
392
|
+
TOutputBroadcast,
|
|
393
|
+
TOutputSelf,
|
|
394
|
+
TOutputSync
|
|
282
395
|
>(room, {
|
|
283
396
|
authorize: this._authorize ?? undefined,
|
|
284
397
|
context: this._context,
|
|
@@ -291,6 +404,7 @@ export class PluvIO<
|
|
|
291
404
|
);
|
|
292
405
|
|
|
293
406
|
this._rooms.delete(room);
|
|
407
|
+
this._listeners.onRoomDeleted(room, encodedState);
|
|
294
408
|
|
|
295
409
|
if (this._debug) {
|
|
296
410
|
const rooms = Array.from(this._rooms.keys());
|
|
@@ -300,12 +414,6 @@ export class PluvIO<
|
|
|
300
414
|
`${colors.blue("Rooms available:")} ${rooms.join(", ")}`
|
|
301
415
|
);
|
|
302
416
|
}
|
|
303
|
-
|
|
304
|
-
this._platform.persistance.getSize(room).then((size) => {
|
|
305
|
-
if (size) return;
|
|
306
|
-
|
|
307
|
-
this._listeners.onRoomDeleted(room, encodedState);
|
|
308
|
-
});
|
|
309
417
|
},
|
|
310
418
|
platform,
|
|
311
419
|
});
|
|
@@ -332,7 +440,9 @@ export class PluvIO<
|
|
|
332
440
|
InferIOAuthorize<TIO1>,
|
|
333
441
|
InferIOContext<TIO1>,
|
|
334
442
|
Spread<[InferIOInput<TIO1>, InferIOInput<TIO2>]>,
|
|
335
|
-
Spread<[
|
|
443
|
+
Spread<[InferIOOutputBroadcast<TIO1>, InferIOOutputBroadcast<TIO2>]>,
|
|
444
|
+
Spread<[InferIOOutputSelf<TIO1>, InferIOOutputSelf<TIO2>]>,
|
|
445
|
+
Spread<[InferIOOutputSync<TIO1>, InferIOOutputSync<TIO2>]>
|
|
336
446
|
> {
|
|
337
447
|
const authorize = (first._authorize ??
|
|
338
448
|
undefined) as InferIOAuthorize<TIO1>;
|
package/src/types.ts
CHANGED
|
@@ -25,11 +25,20 @@ declare global {
|
|
|
25
25
|
export interface EventConfig<
|
|
26
26
|
TContext extends JsonObject = {},
|
|
27
27
|
TData extends JsonObject = {},
|
|
28
|
-
|
|
28
|
+
TResultBroadcast extends EventRecord<string, any> = {},
|
|
29
|
+
TResultSelf extends EventRecord<string, any> = {},
|
|
30
|
+
TResultSync extends EventRecord<string, any> = {}
|
|
29
31
|
> {
|
|
30
32
|
input?: InputZodLike<TData>;
|
|
31
|
-
|
|
32
|
-
|
|
33
|
+
resolver:
|
|
34
|
+
| EventResolver<TContext, TData, TResultBroadcast>
|
|
35
|
+
| EventResolverObject<
|
|
36
|
+
TContext,
|
|
37
|
+
TData,
|
|
38
|
+
TResultBroadcast,
|
|
39
|
+
TResultSelf,
|
|
40
|
+
TResultSync
|
|
41
|
+
>;
|
|
33
42
|
}
|
|
34
43
|
|
|
35
44
|
export type EventConfigType = "broadcast" | "self" | "sync";
|
|
@@ -37,11 +46,11 @@ export type EventConfigType = "broadcast" | "self" | "sync";
|
|
|
37
46
|
export type EventResolver<
|
|
38
47
|
TContext extends JsonObject = {},
|
|
39
48
|
TData extends JsonObject = {},
|
|
40
|
-
|
|
49
|
+
TResultBroadcast extends EventRecord<string, any> = {}
|
|
41
50
|
> = (
|
|
42
51
|
data: TData,
|
|
43
52
|
context: EventResolverContext<TContext>
|
|
44
|
-
) => MaybePromise<
|
|
53
|
+
) => MaybePromise<TResultBroadcast | void>;
|
|
45
54
|
|
|
46
55
|
export interface EventResolverContext<TContext extends JsonObject = {}> {
|
|
47
56
|
context: TContext;
|
|
@@ -63,13 +72,35 @@ export interface EventResolverContext<TContext extends JsonObject = {}> {
|
|
|
63
72
|
sessions: Map<string, WebSocketSession>;
|
|
64
73
|
}
|
|
65
74
|
|
|
75
|
+
export type EventResolverObject<
|
|
76
|
+
TContext extends JsonObject = {},
|
|
77
|
+
TData extends JsonObject = {},
|
|
78
|
+
TResultBroadcast extends EventRecord<string, any> = {},
|
|
79
|
+
TResultSelf extends EventRecord<string, any> = {},
|
|
80
|
+
TResultSync extends EventRecord<string, any> = {}
|
|
81
|
+
> = {
|
|
82
|
+
broadcast?: EventResolver<TContext, TData, TResultBroadcast>;
|
|
83
|
+
self?: EventResolver<TContext, TData, TResultSelf>;
|
|
84
|
+
sync?: EventResolver<TContext, TData, TResultSync>;
|
|
85
|
+
};
|
|
86
|
+
|
|
66
87
|
export type InferEventConfig<
|
|
67
88
|
TContext extends JsonObject = {},
|
|
68
89
|
TInput extends EventRecord<string, any> = {},
|
|
69
|
-
|
|
90
|
+
TOutputBroadcast extends EventRecord<string, any> = {},
|
|
91
|
+
TOutputSelf extends EventRecord<string, any> = {},
|
|
92
|
+
TOutputSync extends EventRecord<string, any> = {}
|
|
70
93
|
> = {
|
|
71
94
|
[P in keyof TInput]: P extends string
|
|
72
|
-
? Id<
|
|
95
|
+
? Id<
|
|
96
|
+
EventConfig<
|
|
97
|
+
TContext,
|
|
98
|
+
TInput[P],
|
|
99
|
+
TOutputBroadcast,
|
|
100
|
+
TOutputSelf,
|
|
101
|
+
TOutputSync
|
|
102
|
+
>
|
|
103
|
+
>
|
|
73
104
|
: never;
|
|
74
105
|
};
|
|
75
106
|
|