@pluv/io 0.40.2 → 0.41.1
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 +69 -0
- package/dist/index.d.mts +30 -21
- package/dist/index.d.ts +30 -21
- package/dist/index.js +198 -75
- package/dist/index.mjs +198 -75
- package/package.json +7 -7
- package/src/AbstractPlatform.ts +3 -3
- package/src/AbstractWebSocket.ts +3 -20
- package/src/IORoom.ts +248 -65
- package/src/PluvServer.ts +39 -12
- package/src/authorize.ts +4 -4
- package/src/constants.ts +3 -0
- package/src/types.ts +4 -8
- package/src/version.generated.ts +1 -1
- package/tsconfig.json +5 -1
package/src/PluvServer.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import type { AbstractCrdtDocFactory } from "@pluv/crdt";
|
|
2
2
|
import { noop } from "@pluv/crdt";
|
|
3
|
-
import type { IOLike, Id, InferIOAuthorize, InferIOAuthorizeUser, JsonObject, Maybe } from "@pluv/types";
|
|
3
|
+
import type { BaseUser, IOLike, Id, InferIOAuthorize, InferIOAuthorizeUser, JsonObject, Maybe } from "@pluv/types";
|
|
4
4
|
import colors from "kleur";
|
|
5
5
|
import type { AbstractPlatform, InferInitContextType, InferRoomContextType } from "./AbstractPlatform";
|
|
6
6
|
import type { IORoomListeners, WebSocketRegisterConfig } from "./IORoom";
|
|
@@ -10,7 +10,7 @@ import type { PluvRouterEventConfig } from "./PluvRouter";
|
|
|
10
10
|
import { PluvRouter } from "./PluvRouter";
|
|
11
11
|
import type { JWTEncodeParams } from "./authorize";
|
|
12
12
|
import { authorize } from "./authorize";
|
|
13
|
-
import { PING_TIMEOUT_MS } from "./constants";
|
|
13
|
+
import { MAX_PRESENCE_SIZE_BYTES, MAX_USER_SIZE_BYTES, PING_TIMEOUT_MS } from "./constants";
|
|
14
14
|
import type {
|
|
15
15
|
BasePluvIOListeners,
|
|
16
16
|
GetInitialStorageFn,
|
|
@@ -27,7 +27,7 @@ export type InferIORoom<TServer extends PluvServer<any, any, any, any>> =
|
|
|
27
27
|
: never;
|
|
28
28
|
|
|
29
29
|
export type PluvServerConfig<
|
|
30
|
-
TPlatform extends AbstractPlatform<any> = AbstractPlatform<any>,
|
|
30
|
+
TPlatform extends AbstractPlatform<any, any> = AbstractPlatform<any, any>,
|
|
31
31
|
TAuthorize extends PluvIOAuthorize<TPlatform, any, InferInitContextType<TPlatform>> | null = any,
|
|
32
32
|
TContext extends Record<string, any> = {},
|
|
33
33
|
TEvents extends PluvRouterEventConfig<TPlatform, TAuthorize, TContext> = {},
|
|
@@ -42,7 +42,7 @@ export type PluvServerConfig<
|
|
|
42
42
|
};
|
|
43
43
|
|
|
44
44
|
type BaseCreateRoomOptions<
|
|
45
|
-
TPlatform extends AbstractPlatform<any>,
|
|
45
|
+
TPlatform extends AbstractPlatform<any, any>,
|
|
46
46
|
TAuthorize extends PluvIOAuthorize<TPlatform, any, InferInitContextType<TPlatform>> | null,
|
|
47
47
|
TContext extends Record<string, any>,
|
|
48
48
|
TEvents extends PluvRouterEventConfig<TPlatform, TAuthorize, TContext>,
|
|
@@ -51,7 +51,7 @@ type BaseCreateRoomOptions<
|
|
|
51
51
|
};
|
|
52
52
|
|
|
53
53
|
export type CreateRoomOptions<
|
|
54
|
-
TPlatform extends AbstractPlatform<any>,
|
|
54
|
+
TPlatform extends AbstractPlatform<any, any>,
|
|
55
55
|
TAuthorize extends PluvIOAuthorize<TPlatform, any, InferInitContextType<TPlatform>> | null,
|
|
56
56
|
TContext extends Record<string, any>,
|
|
57
57
|
TEvents extends PluvRouterEventConfig<TPlatform, TAuthorize, TContext>,
|
|
@@ -60,7 +60,7 @@ export type CreateRoomOptions<
|
|
|
60
60
|
: [Id<BaseCreateRoomOptions<TPlatform, TAuthorize, TContext, TEvents> & InferRoomContextType<TPlatform>>];
|
|
61
61
|
|
|
62
62
|
export class PluvServer<
|
|
63
|
-
TPlatform extends AbstractPlatform<any> = AbstractPlatform<any>,
|
|
63
|
+
TPlatform extends AbstractPlatform<any, any> = AbstractPlatform<any, any>,
|
|
64
64
|
TAuthorize extends PluvIOAuthorize<TPlatform, any, InferInitContextType<TPlatform>> | null = any,
|
|
65
65
|
TContext extends Record<string, any> = {},
|
|
66
66
|
TEvents extends PluvRouterEventConfig<TPlatform, TAuthorize, TContext> = {},
|
|
@@ -88,12 +88,13 @@ export class PluvServer<
|
|
|
88
88
|
user: JsonObject | null;
|
|
89
89
|
};
|
|
90
90
|
}>(
|
|
91
|
-
(acc, { id, presence, user }) => ({
|
|
91
|
+
(acc, { id, presence, timers, user }) => ({
|
|
92
92
|
...acc,
|
|
93
93
|
[id]: {
|
|
94
94
|
connectionId: id,
|
|
95
95
|
presence,
|
|
96
96
|
room,
|
|
97
|
+
timers: { presence: timers.presence },
|
|
97
98
|
user,
|
|
98
99
|
},
|
|
99
100
|
}),
|
|
@@ -105,6 +106,7 @@ export class PluvServer<
|
|
|
105
106
|
$initializeSession: this._procedure
|
|
106
107
|
.broadcast((data, { session }) => {
|
|
107
108
|
const presence = (data as any)?.presence;
|
|
109
|
+
const timers = session.timers;
|
|
108
110
|
|
|
109
111
|
if (!session) return {};
|
|
110
112
|
|
|
@@ -115,6 +117,7 @@ export class PluvServer<
|
|
|
115
117
|
connectionId: session.id,
|
|
116
118
|
user: session.user,
|
|
117
119
|
presence,
|
|
120
|
+
timers: { presence: timers.presence },
|
|
118
121
|
},
|
|
119
122
|
};
|
|
120
123
|
})
|
|
@@ -161,16 +164,29 @@ export class PluvServer<
|
|
|
161
164
|
|
|
162
165
|
return { $pong: {} };
|
|
163
166
|
}),
|
|
164
|
-
$updatePresence: this._procedure.broadcast((data,
|
|
167
|
+
$updatePresence: this._procedure.broadcast((data, context) => {
|
|
165
168
|
const presence = (data as any)?.presence;
|
|
169
|
+
const { session } = context;
|
|
166
170
|
|
|
167
171
|
if (!session) return {};
|
|
168
172
|
|
|
169
173
|
const updated = Object.assign(Object.create(null), session.presence, presence);
|
|
174
|
+
const bytes = new TextEncoder().encode(JSON.stringify(updated)).length;
|
|
170
175
|
|
|
171
|
-
|
|
176
|
+
if (bytes > MAX_PRESENCE_SIZE_BYTES) {
|
|
177
|
+
throw new Error(
|
|
178
|
+
`Large presence. Presence must be at most 512 bytes. Current size: ${bytes.toLocaleString()}`,
|
|
179
|
+
);
|
|
180
|
+
}
|
|
181
|
+
|
|
182
|
+
context.presence = updated;
|
|
172
183
|
|
|
173
|
-
return {
|
|
184
|
+
return {
|
|
185
|
+
$presenceUpdated: {
|
|
186
|
+
presence: updated,
|
|
187
|
+
timers: { presence: session.timers.presence },
|
|
188
|
+
},
|
|
189
|
+
};
|
|
174
190
|
}),
|
|
175
191
|
$updateStorage: this._procedure.broadcast((data, { context, doc, room }) => {
|
|
176
192
|
const origin = (data as any)?.origin as Maybe<string>;
|
|
@@ -331,15 +347,26 @@ export class PluvServer<
|
|
|
331
347
|
throw new Error("IO does not specify authorize during initialization.");
|
|
332
348
|
}
|
|
333
349
|
|
|
350
|
+
const ioAuthorize = this._getIOAuthorize(params);
|
|
351
|
+
const user = params.user as BaseUser;
|
|
352
|
+
const parsed = !!ioAuthorize ? ioAuthorize.user.parse(user) : user;
|
|
353
|
+
|
|
354
|
+
const bytes = new TextEncoder().encode(JSON.stringify(parsed)).length;
|
|
355
|
+
|
|
356
|
+
if (bytes > MAX_USER_SIZE_BYTES) {
|
|
357
|
+
throw new Error(
|
|
358
|
+
`createToken called with large payload. User must be at most 512 bytes. Current size: ${bytes.toLocaleString()}`,
|
|
359
|
+
);
|
|
360
|
+
}
|
|
361
|
+
|
|
334
362
|
/**
|
|
335
363
|
* !HACK
|
|
336
364
|
* @description Allow the platform to overwrite this behavior as needed. This is introduced
|
|
337
365
|
* to support platformPluv
|
|
338
366
|
* @date December 15, 2024
|
|
339
367
|
*/
|
|
340
|
-
if (this._platform._createToken) return await this._platform._createToken(params);
|
|
368
|
+
if (this._platform._createToken) return await this._platform._createToken(params as any);
|
|
341
369
|
|
|
342
|
-
const ioAuthorize = this._getIOAuthorize(params);
|
|
343
370
|
const secret = ioAuthorize?.secret ?? null;
|
|
344
371
|
|
|
345
372
|
if (!secret) throw new Error("`authorize` was specified without a valid secret");
|
package/src/authorize.ts
CHANGED
|
@@ -15,20 +15,20 @@ export interface JWT<TUser extends BaseUser> {
|
|
|
15
15
|
user: TUser;
|
|
16
16
|
}
|
|
17
17
|
|
|
18
|
-
export type JWTEncodeParams<TUser extends BaseUser | null, TPlatform extends AbstractPlatform
|
|
18
|
+
export type JWTEncodeParams<TUser extends BaseUser | null, TPlatform extends AbstractPlatform<any, any>> = {
|
|
19
19
|
maxAge?: number;
|
|
20
20
|
room: string;
|
|
21
21
|
user: TUser extends BaseUser ? TUser : "Error: Cannot create token without authorization!";
|
|
22
22
|
} & InferInitContextType<TPlatform>;
|
|
23
23
|
|
|
24
24
|
export interface AuthorizeParams {
|
|
25
|
-
platform: AbstractPlatform
|
|
25
|
+
platform: AbstractPlatform<any, any>;
|
|
26
26
|
secret: string;
|
|
27
27
|
}
|
|
28
28
|
|
|
29
29
|
export interface AuthorizeModule {
|
|
30
30
|
decode: <TUser extends BaseUser>(jwt: string) => Promise<TUser | null>;
|
|
31
|
-
encode: <TUser extends BaseUser, TPlatform extends AbstractPlatform
|
|
31
|
+
encode: <TUser extends BaseUser, TPlatform extends AbstractPlatform<any, any>>(
|
|
32
32
|
params: JWTEncodeParams<TUser, TPlatform>,
|
|
33
33
|
) => Promise<string>;
|
|
34
34
|
}
|
|
@@ -38,7 +38,7 @@ const now = () => (Date.now() / 1_000) | 0;
|
|
|
38
38
|
export const authorize = (params: AuthorizeParams) => {
|
|
39
39
|
const { platform, secret } = params;
|
|
40
40
|
|
|
41
|
-
const encode = async <TUser extends BaseUser, TPlatform extends AbstractPlatform
|
|
41
|
+
const encode = async <TUser extends BaseUser, TPlatform extends AbstractPlatform<any, any>>(
|
|
42
42
|
encodeParams: JWTEncodeParams<TUser, TPlatform>,
|
|
43
43
|
): Promise<string> => {
|
|
44
44
|
const { maxAge = DEFAULT_MAX_AGE_MS, room, user } = encodeParams;
|
package/src/constants.ts
CHANGED
package/src/types.ts
CHANGED
|
@@ -23,14 +23,6 @@ import type {
|
|
|
23
23
|
import type { AbstractWebSocket } from "./AbstractWebSocket";
|
|
24
24
|
import type { PluvRouter, PluvRouterEventConfig } from "./PluvRouter";
|
|
25
25
|
|
|
26
|
-
declare global {
|
|
27
|
-
// eslint-disable-next-line no-var
|
|
28
|
-
var console: {
|
|
29
|
-
error: (...data: any[]) => void;
|
|
30
|
-
log: (...data: any[]) => void;
|
|
31
|
-
};
|
|
32
|
-
}
|
|
33
|
-
|
|
34
26
|
export type PluvContext<TPlatform extends AbstractPlatform, TContext extends Record<string, any>> =
|
|
35
27
|
| TContext
|
|
36
28
|
| ((params: InferRoomContextType<TPlatform>) => TContext);
|
|
@@ -62,9 +54,12 @@ export interface EventResolverContext<
|
|
|
62
54
|
> {
|
|
63
55
|
context: TContext;
|
|
64
56
|
doc: AbstractCrdtDoc<any>;
|
|
57
|
+
garbageCollect: () => Promise<void>;
|
|
58
|
+
presence: JsonObject | null;
|
|
65
59
|
room: string;
|
|
66
60
|
session: TKind extends "sync" ? WebSocketSession<TAuthorize> | null : WebSocketSession<TAuthorize>;
|
|
67
61
|
sessions: readonly WebSocketSession<TAuthorize>[];
|
|
62
|
+
time: number;
|
|
68
63
|
}
|
|
69
64
|
|
|
70
65
|
export type SendMessageOptions =
|
|
@@ -74,6 +69,7 @@ export type SendMessageOptions =
|
|
|
74
69
|
|
|
75
70
|
export interface WebSocketSessionTimers {
|
|
76
71
|
ping: number;
|
|
72
|
+
presence: number | null;
|
|
77
73
|
}
|
|
78
74
|
|
|
79
75
|
export interface WebSocketSerializedState {
|
package/src/version.generated.ts
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
1
|
// Generated by genversion.
|
|
2
|
-
export const version = '0.
|
|
2
|
+
export const version = '0.41.1'
|