@pluv/io 0.42.0 → 0.44.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 +44 -0
- package/dist/index.d.mts +26 -2
- package/dist/index.d.ts +26 -2
- package/dist/index.js +48 -31
- package/dist/index.mjs +48 -31
- package/package.json +5 -5
- package/src/PluvIO.ts +40 -2
- package/src/PluvServer.ts +29 -45
- package/src/constants.ts +2 -0
- package/src/createIO.ts +4 -2
- package/src/index.ts +1 -0
- package/src/types.ts +19 -0
- package/src/version.generated.ts +1 -1
package/.turbo/turbo-build.log
CHANGED
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
|
|
2
|
-
> @pluv/io@0.
|
|
2
|
+
> @pluv/io@0.44.0 build /home/runner/work/pluv/pluv/packages/io
|
|
3
3
|
> pnpm run version && tsup src/index.ts --format esm,cjs --dts
|
|
4
4
|
|
|
5
5
|
|
|
6
|
-
> @pluv/io@0.
|
|
6
|
+
> @pluv/io@0.44.0 version /home/runner/work/pluv/pluv/packages/io
|
|
7
7
|
> genversion ./src/version.generated.ts --esm
|
|
8
8
|
|
|
9
9
|
[34mCLI[39m Building entry: src/index.ts
|
|
@@ -12,11 +12,11 @@
|
|
|
12
12
|
[34mCLI[39m Target: es6
|
|
13
13
|
[34mESM[39m Build start
|
|
14
14
|
[34mCJS[39m Build start
|
|
15
|
-
[
|
|
16
|
-
[
|
|
17
|
-
[
|
|
18
|
-
[
|
|
15
|
+
[32mCJS[39m [1mdist/index.js [22m[32m52.90 KB[39m
|
|
16
|
+
[32mCJS[39m ⚡️ Build success in 142ms
|
|
17
|
+
[32mESM[39m [1mdist/index.mjs [22m[32m50.73 KB[39m
|
|
18
|
+
[32mESM[39m ⚡️ Build success in 143ms
|
|
19
19
|
[34mDTS[39m Build start
|
|
20
|
-
[32mDTS[39m ⚡️ Build success in
|
|
21
|
-
[32mDTS[39m [1mdist/index.d.mts [22m[
|
|
22
|
-
[32mDTS[39m [1mdist/index.d.ts [22m[
|
|
20
|
+
[32mDTS[39m ⚡️ Build success in 3191ms
|
|
21
|
+
[32mDTS[39m [1mdist/index.d.mts [22m[32m32.19 KB[39m
|
|
22
|
+
[32mDTS[39m [1mdist/index.d.ts [22m[32m32.19 KB[39m
|
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,49 @@
|
|
|
1
1
|
# @pluv/io
|
|
2
2
|
|
|
3
|
+
## 0.44.0
|
|
4
|
+
|
|
5
|
+
### Patch Changes
|
|
6
|
+
|
|
7
|
+
- @pluv/crdt@0.44.0
|
|
8
|
+
- @pluv/types@0.44.0
|
|
9
|
+
|
|
10
|
+
## 0.43.0
|
|
11
|
+
|
|
12
|
+
### Minor Changes
|
|
13
|
+
|
|
14
|
+
- 0063e80: **BREAKING** Added a configurable limit for the max-size (in bytes) for storage (defaulting to 30MB). To unset this limit, you can set this limit to `0` or `null`.
|
|
15
|
+
|
|
16
|
+
```ts
|
|
17
|
+
createIO({
|
|
18
|
+
limits: {
|
|
19
|
+
storageMaxSize: null,
|
|
20
|
+
},
|
|
21
|
+
});
|
|
22
|
+
```
|
|
23
|
+
|
|
24
|
+
- 4b0fbb3: **BREAKING** Added the ability to configure the limits for user object size, presence size, and user id length. User id is now defaulted to be limited to 128 characters. To unset this limit, you can set this limit to `0` or `null`.
|
|
25
|
+
|
|
26
|
+
```ts
|
|
27
|
+
// defaults
|
|
28
|
+
createIO(
|
|
29
|
+
platformCloudflare({
|
|
30
|
+
limits: {
|
|
31
|
+
presenceMaxSize: 512,
|
|
32
|
+
storageMaxSize: 31_457_280,
|
|
33
|
+
userIdMaxLength: 128,
|
|
34
|
+
userMaxSize: 512,
|
|
35
|
+
},
|
|
36
|
+
}),
|
|
37
|
+
);
|
|
38
|
+
```
|
|
39
|
+
|
|
40
|
+
### Patch Changes
|
|
41
|
+
|
|
42
|
+
- e60a677: Fix 1 and 2 character long room names not being supported.
|
|
43
|
+
- 244a973: Fixed not applying user size limits when calling `PluvIO.authorize` and not allowing it to be overwritten for `platformPluv`.
|
|
44
|
+
- @pluv/crdt@0.43.0
|
|
45
|
+
- @pluv/types@0.43.0
|
|
46
|
+
|
|
3
47
|
## 0.42.0
|
|
4
48
|
|
|
5
49
|
### Patch Changes
|
package/dist/index.d.mts
CHANGED
|
@@ -195,6 +195,24 @@ type ResolvedPluvIOAuthorize<TPlatform extends AbstractPlatform<any, any, any, a
|
|
|
195
195
|
secret?: string;
|
|
196
196
|
}, Exclude<"secret", InferPlatformAuthorizeProperties<TPlatform>>>;
|
|
197
197
|
type PluvIOAuthorize<TPlatform extends AbstractPlatform<any, any, any, any>, TUser extends BaseUser | null = any, TContext extends Record<string, unknown> = {}> = (TUser extends BaseUser ? ResolvedPluvIOAuthorize<TPlatform, TUser> : null) | ((context: TContext) => TUser extends BaseUser ? ResolvedPluvIOAuthorize<TPlatform, TUser> : null);
|
|
198
|
+
interface PluvIOLimits {
|
|
199
|
+
/**
|
|
200
|
+
* @description Maximum size of presence object in bytes
|
|
201
|
+
*/
|
|
202
|
+
presenceMaxSize?: number | null;
|
|
203
|
+
/**
|
|
204
|
+
* @description Maximum size of storage state in bytes
|
|
205
|
+
*/
|
|
206
|
+
storageMaxSize?: number | null;
|
|
207
|
+
/**
|
|
208
|
+
* @description Maximum length of user id in characters
|
|
209
|
+
*/
|
|
210
|
+
userIdMaxLength?: number | null;
|
|
211
|
+
/**
|
|
212
|
+
* @description Maximum size of user object in bytes
|
|
213
|
+
*/
|
|
214
|
+
userMaxSize?: number | null;
|
|
215
|
+
}
|
|
198
216
|
type BasePluvIOListeners<TPlatform extends AbstractPlatform<any, any, any, any>, TAuthorize extends PluvIOAuthorize<TPlatform, any, InferInitContextType<TPlatform>> | null, TContext extends Record<string, any>, TEvents extends PluvRouterEventConfig<TPlatform, TAuthorize, TContext>> = {
|
|
199
217
|
onRoomDeleted: (event: IORoomListenerEvent<TContext>) => void;
|
|
200
218
|
onRoomMessage: (event: IORoomMessageEvent<TPlatform, TAuthorize, TContext, TEvents>) => void;
|
|
@@ -419,6 +437,8 @@ type PluvServerConfig<TPlatform extends AbstractPlatform<any, any> = AbstractPla
|
|
|
419
437
|
};
|
|
420
438
|
debug?: boolean;
|
|
421
439
|
getInitialStorage?: GetInitialStorageFn<TContext>;
|
|
440
|
+
limits: PluvIOLimits;
|
|
441
|
+
io: PluvIO<TPlatform, TAuthorize, TContext>;
|
|
422
442
|
platform: TPlatform;
|
|
423
443
|
router?: PluvRouter<TPlatform, TAuthorize, TContext, TEvents>;
|
|
424
444
|
};
|
|
@@ -434,6 +454,8 @@ declare class PluvServer<TPlatform extends AbstractPlatform<any, any> = Abstract
|
|
|
434
454
|
private readonly _crdt;
|
|
435
455
|
private readonly _debug;
|
|
436
456
|
private readonly _getInitialStorage;
|
|
457
|
+
private readonly _io;
|
|
458
|
+
private readonly _limits;
|
|
437
459
|
private readonly _platform;
|
|
438
460
|
private readonly _router;
|
|
439
461
|
get fetch(): (...args: any[]) => Promise<any>;
|
|
@@ -452,7 +474,6 @@ declare class PluvServer<TPlatform extends AbstractPlatform<any, any> = Abstract
|
|
|
452
474
|
constructor(options: PluvServerConfig<TPlatform, TAuthorize, TContext, TEvents>);
|
|
453
475
|
createRoom(room: string, ...options: CreateRoomOptions<TPlatform, TAuthorize, TContext, TEvents>): IORoom<TPlatform, TAuthorize, TContext, TEvents>;
|
|
454
476
|
createToken(params: JWTEncodeParams<InferIOAuthorizeUser<InferIOAuthorize<this>>, TPlatform>): Promise<string>;
|
|
455
|
-
private _getIOAuthorize;
|
|
456
477
|
private _getListeners;
|
|
457
478
|
private _logDebug;
|
|
458
479
|
}
|
|
@@ -462,6 +483,7 @@ type PluvIOConfig<TPlatform extends AbstractPlatform<any>, TAuthorize extends IO
|
|
|
462
483
|
context?: PluvContext<TPlatform, TContext>;
|
|
463
484
|
crdt?: CrdtLibraryType;
|
|
464
485
|
debug?: boolean;
|
|
486
|
+
limits?: PluvIOLimits;
|
|
465
487
|
platform: TPlatform;
|
|
466
488
|
};
|
|
467
489
|
type ResolvedServerConfig<TPlatform extends AbstractPlatform<any> = AbstractPlatform<any>, TAuthorize extends PluvIOAuthorize<TPlatform, any, InferInitContextType<TPlatform>> | null = any, TContext extends Record<string, any> = {}, TEvents extends PluvRouterEventConfig<TPlatform, TAuthorize, TContext> = {}> = Partial<PluvIOListeners<TPlatform, TAuthorize, TContext, TEvents>> & PluvIORouter<TPlatform, TAuthorize, TContext, TEvents> & {
|
|
@@ -476,6 +498,7 @@ declare class PluvIO<TPlatform extends AbstractPlatform<any> = AbstractPlatform<
|
|
|
476
498
|
private readonly _context;
|
|
477
499
|
private readonly _crdt;
|
|
478
500
|
private readonly _debug;
|
|
501
|
+
private readonly _limits;
|
|
479
502
|
private readonly _platform;
|
|
480
503
|
get procedure(): PluvProcedure<TPlatform, TAuthorize, TContext, {}, {}>;
|
|
481
504
|
constructor(options: PluvIOConfig<TPlatform, TAuthorize, TContext>);
|
|
@@ -491,8 +514,9 @@ type CreateIOParams<TPlatform extends AbstractPlatform<any> = AbstractPlatform<a
|
|
|
491
514
|
context?: PluvContext<TPlatform, TContext>;
|
|
492
515
|
crdt?: CrdtLibraryType;
|
|
493
516
|
debug?: boolean;
|
|
517
|
+
limits?: PluvIOLimits;
|
|
494
518
|
platform: TPlatform;
|
|
495
519
|
};
|
|
496
520
|
declare const createIO: <TPlatform extends AbstractPlatform<any> = AbstractPlatform<any>, TContext extends Record<string, any> = {}, TUser extends BaseUser | null = null>(params: CreateIOParams<TPlatform, TContext, TUser>) => PluvIO<TPlatform, PluvIOAuthorize<TPlatform, TUser, InferInitContextType<TPlatform>>, TContext>;
|
|
497
521
|
|
|
498
|
-
export { type AbstractCloseEvent, type AbstractErrorEvent, type AbstractEvent, type AbstractEventMap, type AbstractListener, type AbstractMessageEvent, AbstractPersistence, AbstractPlatform, type AbstractPlatformConfig, AbstractPubSub, AbstractWebSocket, type AbstractWebSocketConfig, type AbstractWebSocketHandleErrorParams, type AuthorizeModule, type AuthorizeParams, type ConvertWebSocketConfig, type CrdtLibraryType, type CreateIOParams, type CreateRoomOptions, type GetInitialStorageFn, type HandleMode, type IOPubSubEventMessage, IORoom, type IORoomListenerEvent, type IORoomMessageEvent, type IOStorageUpdatedEvent, type IOUserConnectedEvent, type IOUserDisconnectedEvent, type InferIORoom, type InferInitContextType, type InferPlatformWebSocketType, type InferRoomContextType, type JWT, type JWTEncodeParams, type MergedRouter, type PlatformConfig, type PluvContext, PluvIO, type PluvIOAuthorize, type PluvIOConfig, type PluvIOListeners, PluvProcedure, type PluvProcedureConfig, PluvRouter, type PluvRouterEventConfig, PluvServer, type PluvServerConfig, type ServerConfig, type WebSocketRegistrationMode, type WebSocketSerializedState, type WebSocketSession, authorize, createIO };
|
|
522
|
+
export { type AbstractCloseEvent, type AbstractErrorEvent, type AbstractEvent, type AbstractEventMap, type AbstractListener, type AbstractMessageEvent, AbstractPersistence, AbstractPlatform, type AbstractPlatformConfig, AbstractPubSub, AbstractWebSocket, type AbstractWebSocketConfig, type AbstractWebSocketHandleErrorParams, type AuthorizeModule, type AuthorizeParams, type ConvertWebSocketConfig, type CrdtLibraryType, type CreateIOParams, type CreateRoomOptions, type GetInitialStorageFn, type HandleMode, type IOPubSubEventMessage, IORoom, type IORoomListenerEvent, type IORoomMessageEvent, type IOStorageUpdatedEvent, type IOUserConnectedEvent, type IOUserDisconnectedEvent, type InferIORoom, type InferInitContextType, type InferPlatformWebSocketType, type InferRoomContextType, type JWT, type JWTEncodeParams, type MergedRouter, type PlatformConfig, type PluvContext, PluvIO, type PluvIOAuthorize, type PluvIOConfig, type PluvIOLimits, type PluvIOListeners, PluvProcedure, type PluvProcedureConfig, PluvRouter, type PluvRouterEventConfig, PluvServer, type PluvServerConfig, type ServerConfig, type WebSocketRegistrationMode, type WebSocketSerializedState, type WebSocketSession, authorize, createIO };
|
package/dist/index.d.ts
CHANGED
|
@@ -195,6 +195,24 @@ type ResolvedPluvIOAuthorize<TPlatform extends AbstractPlatform<any, any, any, a
|
|
|
195
195
|
secret?: string;
|
|
196
196
|
}, Exclude<"secret", InferPlatformAuthorizeProperties<TPlatform>>>;
|
|
197
197
|
type PluvIOAuthorize<TPlatform extends AbstractPlatform<any, any, any, any>, TUser extends BaseUser | null = any, TContext extends Record<string, unknown> = {}> = (TUser extends BaseUser ? ResolvedPluvIOAuthorize<TPlatform, TUser> : null) | ((context: TContext) => TUser extends BaseUser ? ResolvedPluvIOAuthorize<TPlatform, TUser> : null);
|
|
198
|
+
interface PluvIOLimits {
|
|
199
|
+
/**
|
|
200
|
+
* @description Maximum size of presence object in bytes
|
|
201
|
+
*/
|
|
202
|
+
presenceMaxSize?: number | null;
|
|
203
|
+
/**
|
|
204
|
+
* @description Maximum size of storage state in bytes
|
|
205
|
+
*/
|
|
206
|
+
storageMaxSize?: number | null;
|
|
207
|
+
/**
|
|
208
|
+
* @description Maximum length of user id in characters
|
|
209
|
+
*/
|
|
210
|
+
userIdMaxLength?: number | null;
|
|
211
|
+
/**
|
|
212
|
+
* @description Maximum size of user object in bytes
|
|
213
|
+
*/
|
|
214
|
+
userMaxSize?: number | null;
|
|
215
|
+
}
|
|
198
216
|
type BasePluvIOListeners<TPlatform extends AbstractPlatform<any, any, any, any>, TAuthorize extends PluvIOAuthorize<TPlatform, any, InferInitContextType<TPlatform>> | null, TContext extends Record<string, any>, TEvents extends PluvRouterEventConfig<TPlatform, TAuthorize, TContext>> = {
|
|
199
217
|
onRoomDeleted: (event: IORoomListenerEvent<TContext>) => void;
|
|
200
218
|
onRoomMessage: (event: IORoomMessageEvent<TPlatform, TAuthorize, TContext, TEvents>) => void;
|
|
@@ -419,6 +437,8 @@ type PluvServerConfig<TPlatform extends AbstractPlatform<any, any> = AbstractPla
|
|
|
419
437
|
};
|
|
420
438
|
debug?: boolean;
|
|
421
439
|
getInitialStorage?: GetInitialStorageFn<TContext>;
|
|
440
|
+
limits: PluvIOLimits;
|
|
441
|
+
io: PluvIO<TPlatform, TAuthorize, TContext>;
|
|
422
442
|
platform: TPlatform;
|
|
423
443
|
router?: PluvRouter<TPlatform, TAuthorize, TContext, TEvents>;
|
|
424
444
|
};
|
|
@@ -434,6 +454,8 @@ declare class PluvServer<TPlatform extends AbstractPlatform<any, any> = Abstract
|
|
|
434
454
|
private readonly _crdt;
|
|
435
455
|
private readonly _debug;
|
|
436
456
|
private readonly _getInitialStorage;
|
|
457
|
+
private readonly _io;
|
|
458
|
+
private readonly _limits;
|
|
437
459
|
private readonly _platform;
|
|
438
460
|
private readonly _router;
|
|
439
461
|
get fetch(): (...args: any[]) => Promise<any>;
|
|
@@ -452,7 +474,6 @@ declare class PluvServer<TPlatform extends AbstractPlatform<any, any> = Abstract
|
|
|
452
474
|
constructor(options: PluvServerConfig<TPlatform, TAuthorize, TContext, TEvents>);
|
|
453
475
|
createRoom(room: string, ...options: CreateRoomOptions<TPlatform, TAuthorize, TContext, TEvents>): IORoom<TPlatform, TAuthorize, TContext, TEvents>;
|
|
454
476
|
createToken(params: JWTEncodeParams<InferIOAuthorizeUser<InferIOAuthorize<this>>, TPlatform>): Promise<string>;
|
|
455
|
-
private _getIOAuthorize;
|
|
456
477
|
private _getListeners;
|
|
457
478
|
private _logDebug;
|
|
458
479
|
}
|
|
@@ -462,6 +483,7 @@ type PluvIOConfig<TPlatform extends AbstractPlatform<any>, TAuthorize extends IO
|
|
|
462
483
|
context?: PluvContext<TPlatform, TContext>;
|
|
463
484
|
crdt?: CrdtLibraryType;
|
|
464
485
|
debug?: boolean;
|
|
486
|
+
limits?: PluvIOLimits;
|
|
465
487
|
platform: TPlatform;
|
|
466
488
|
};
|
|
467
489
|
type ResolvedServerConfig<TPlatform extends AbstractPlatform<any> = AbstractPlatform<any>, TAuthorize extends PluvIOAuthorize<TPlatform, any, InferInitContextType<TPlatform>> | null = any, TContext extends Record<string, any> = {}, TEvents extends PluvRouterEventConfig<TPlatform, TAuthorize, TContext> = {}> = Partial<PluvIOListeners<TPlatform, TAuthorize, TContext, TEvents>> & PluvIORouter<TPlatform, TAuthorize, TContext, TEvents> & {
|
|
@@ -476,6 +498,7 @@ declare class PluvIO<TPlatform extends AbstractPlatform<any> = AbstractPlatform<
|
|
|
476
498
|
private readonly _context;
|
|
477
499
|
private readonly _crdt;
|
|
478
500
|
private readonly _debug;
|
|
501
|
+
private readonly _limits;
|
|
479
502
|
private readonly _platform;
|
|
480
503
|
get procedure(): PluvProcedure<TPlatform, TAuthorize, TContext, {}, {}>;
|
|
481
504
|
constructor(options: PluvIOConfig<TPlatform, TAuthorize, TContext>);
|
|
@@ -491,8 +514,9 @@ type CreateIOParams<TPlatform extends AbstractPlatform<any> = AbstractPlatform<a
|
|
|
491
514
|
context?: PluvContext<TPlatform, TContext>;
|
|
492
515
|
crdt?: CrdtLibraryType;
|
|
493
516
|
debug?: boolean;
|
|
517
|
+
limits?: PluvIOLimits;
|
|
494
518
|
platform: TPlatform;
|
|
495
519
|
};
|
|
496
520
|
declare const createIO: <TPlatform extends AbstractPlatform<any> = AbstractPlatform<any>, TContext extends Record<string, any> = {}, TUser extends BaseUser | null = null>(params: CreateIOParams<TPlatform, TContext, TUser>) => PluvIO<TPlatform, PluvIOAuthorize<TPlatform, TUser, InferInitContextType<TPlatform>>, TContext>;
|
|
497
521
|
|
|
498
|
-
export { type AbstractCloseEvent, type AbstractErrorEvent, type AbstractEvent, type AbstractEventMap, type AbstractListener, type AbstractMessageEvent, AbstractPersistence, AbstractPlatform, type AbstractPlatformConfig, AbstractPubSub, AbstractWebSocket, type AbstractWebSocketConfig, type AbstractWebSocketHandleErrorParams, type AuthorizeModule, type AuthorizeParams, type ConvertWebSocketConfig, type CrdtLibraryType, type CreateIOParams, type CreateRoomOptions, type GetInitialStorageFn, type HandleMode, type IOPubSubEventMessage, IORoom, type IORoomListenerEvent, type IORoomMessageEvent, type IOStorageUpdatedEvent, type IOUserConnectedEvent, type IOUserDisconnectedEvent, type InferIORoom, type InferInitContextType, type InferPlatformWebSocketType, type InferRoomContextType, type JWT, type JWTEncodeParams, type MergedRouter, type PlatformConfig, type PluvContext, PluvIO, type PluvIOAuthorize, type PluvIOConfig, type PluvIOListeners, PluvProcedure, type PluvProcedureConfig, PluvRouter, type PluvRouterEventConfig, PluvServer, type PluvServerConfig, type ServerConfig, type WebSocketRegistrationMode, type WebSocketSerializedState, type WebSocketSession, authorize, createIO };
|
|
522
|
+
export { type AbstractCloseEvent, type AbstractErrorEvent, type AbstractEvent, type AbstractEventMap, type AbstractListener, type AbstractMessageEvent, AbstractPersistence, AbstractPlatform, type AbstractPlatformConfig, AbstractPubSub, AbstractWebSocket, type AbstractWebSocketConfig, type AbstractWebSocketHandleErrorParams, type AuthorizeModule, type AuthorizeParams, type ConvertWebSocketConfig, type CrdtLibraryType, type CreateIOParams, type CreateRoomOptions, type GetInitialStorageFn, type HandleMode, type IOPubSubEventMessage, IORoom, type IORoomListenerEvent, type IORoomMessageEvent, type IOStorageUpdatedEvent, type IOUserConnectedEvent, type IOUserDisconnectedEvent, type InferIORoom, type InferInitContextType, type InferPlatformWebSocketType, type InferRoomContextType, type JWT, type JWTEncodeParams, type MergedRouter, type PlatformConfig, type PluvContext, PluvIO, type PluvIOAuthorize, type PluvIOConfig, type PluvIOLimits, type PluvIOListeners, PluvProcedure, type PluvProcedureConfig, PluvRouter, type PluvRouterEventConfig, PluvServer, type PluvServerConfig, type ServerConfig, type WebSocketRegistrationMode, type WebSocketSerializedState, type WebSocketSession, authorize, createIO };
|
package/dist/index.js
CHANGED
|
@@ -399,6 +399,8 @@ var import_kleur = __toESM(require("kleur"));
|
|
|
399
399
|
// src/constants.ts
|
|
400
400
|
var GARBAGE_COLLECT_INTERVAL_MS = 6e4;
|
|
401
401
|
var MAX_PRESENCE_SIZE_BYTES = 512;
|
|
402
|
+
var MAX_STORAGE_SIZE_BYTES = 31457280;
|
|
403
|
+
var MAX_USER_ID_LENGTH = 128;
|
|
402
404
|
var MAX_USER_SIZE_BYTES = 512;
|
|
403
405
|
var PING_TIMEOUT_MS = 3e4;
|
|
404
406
|
|
|
@@ -1139,7 +1141,7 @@ var pickBy = (obj, by) => {
|
|
|
1139
1141
|
};
|
|
1140
1142
|
|
|
1141
1143
|
// src/version.generated.ts
|
|
1142
|
-
var version = "0.
|
|
1144
|
+
var version = "0.44.0";
|
|
1143
1145
|
|
|
1144
1146
|
// src/PluvServer.ts
|
|
1145
1147
|
var PluvServer = class {
|
|
@@ -1190,18 +1192,22 @@ var PluvServer = class {
|
|
|
1190
1192
|
update
|
|
1191
1193
|
];
|
|
1192
1194
|
if (updates.some((_update) => !!_update)) {
|
|
1193
|
-
const
|
|
1194
|
-
yield this._platform.persistence.setStorageState(room,
|
|
1195
|
+
const encodedState2 = doc.batchApplyEncodedState({ updates }).getEncodedState();
|
|
1196
|
+
yield this._platform.persistence.setStorageState(room, encodedState2);
|
|
1195
1197
|
this._getListeners().onStorageUpdated({
|
|
1196
1198
|
context,
|
|
1197
|
-
encodedState,
|
|
1199
|
+
encodedState: encodedState2,
|
|
1198
1200
|
room,
|
|
1199
1201
|
user: session == null ? void 0 : session.user,
|
|
1200
1202
|
webSocket: session == null ? void 0 : session.webSocket.webSocket
|
|
1201
1203
|
});
|
|
1202
1204
|
}
|
|
1203
|
-
const
|
|
1204
|
-
|
|
1205
|
+
const encodedState = (_b = yield this._platform.persistence.getStorageState(room)) != null ? _b : doc.getEncodedState();
|
|
1206
|
+
const storageSize = new TextEncoder().encode(encodedState).length;
|
|
1207
|
+
if (!!this._limits.storageMaxSize && storageSize > this._limits.storageMaxSize) {
|
|
1208
|
+
throw new Error("Storage has exceeded the size limit");
|
|
1209
|
+
}
|
|
1210
|
+
return { $storageReceived: { state: encodedState } };
|
|
1205
1211
|
})),
|
|
1206
1212
|
$ping: this._procedure.self((data, { session }) => {
|
|
1207
1213
|
if (!session) return {};
|
|
@@ -1221,7 +1227,7 @@ var PluvServer = class {
|
|
|
1221
1227
|
const cleanedPatch = pickBy(presence != null ? presence : {}, (value) => typeof value !== "undefined");
|
|
1222
1228
|
const updated = Object.assign(/* @__PURE__ */ Object.create(null), session.presence, cleanedPatch);
|
|
1223
1229
|
const bytes = new TextEncoder().encode(JSON.stringify(updated)).length;
|
|
1224
|
-
if (bytes >
|
|
1230
|
+
if (!!this._limits.presenceMaxSize && bytes > this._limits.presenceMaxSize) {
|
|
1225
1231
|
throw new Error(
|
|
1226
1232
|
`Large presence. Presence must be at most 512 bytes. Current size: ${bytes.toLocaleString()}`
|
|
1227
1233
|
);
|
|
@@ -1241,6 +1247,10 @@ var PluvServer = class {
|
|
|
1241
1247
|
if (origin === "$initialized" && Object.keys(doc.toJson()).length) return {};
|
|
1242
1248
|
const updated = update === null ? doc : doc.applyEncodedState({ update });
|
|
1243
1249
|
const encodedState = updated.getEncodedState();
|
|
1250
|
+
const storageSize = new TextEncoder().encode(encodedState).length;
|
|
1251
|
+
if (!!this._limits.storageMaxSize && storageSize > this._limits.storageMaxSize) {
|
|
1252
|
+
throw new Error("Storage has exceeded the size limit");
|
|
1253
|
+
}
|
|
1244
1254
|
this._platform.persistence.setStorageState(room, encodedState).then(() => {
|
|
1245
1255
|
this._getListeners().onStorageUpdated({
|
|
1246
1256
|
context,
|
|
@@ -1259,6 +1269,8 @@ var PluvServer = class {
|
|
|
1259
1269
|
crdt = import_crdt2.noop,
|
|
1260
1270
|
debug = false,
|
|
1261
1271
|
getInitialStorage,
|
|
1272
|
+
io,
|
|
1273
|
+
limits,
|
|
1262
1274
|
platform,
|
|
1263
1275
|
router = new PluvRouter({})
|
|
1264
1276
|
} = options;
|
|
@@ -1266,6 +1278,8 @@ var PluvServer = class {
|
|
|
1266
1278
|
platform.validateConfig(options);
|
|
1267
1279
|
this._crdt = crdt;
|
|
1268
1280
|
this._debug = debug;
|
|
1281
|
+
this._io = io;
|
|
1282
|
+
this._limits = limits;
|
|
1269
1283
|
this._platform = platform;
|
|
1270
1284
|
this._router = router ? PluvRouter.merge(this._baseRouter, router) : this._baseRouter;
|
|
1271
1285
|
if (authorize2) this._authorize = authorize2;
|
|
@@ -1307,7 +1321,7 @@ var PluvServer = class {
|
|
|
1307
1321
|
if (this._platform._config.handleMode !== "io") {
|
|
1308
1322
|
throw new Error(`\`createRoom\` is unsupported for \`${this._platform._name}\``);
|
|
1309
1323
|
}
|
|
1310
|
-
if (!/^[a-z0-9]
|
|
1324
|
+
if (!/^[a-z0-9](?:[a-z0-9-_]*[a-z0-9])?$/i.test(room)) throw new Error("Unsupported room name");
|
|
1311
1325
|
const roomContext = platformRoomContext;
|
|
1312
1326
|
const context = typeof this._context === "function" ? this._context(roomContext) : this._context;
|
|
1313
1327
|
const newRoom = new IORoom(room, __spreadProps(__spreadValues({}, !!_meta ? { _meta } : {}), {
|
|
@@ -1341,29 +1355,9 @@ var PluvServer = class {
|
|
|
1341
1355
|
}
|
|
1342
1356
|
createToken(params) {
|
|
1343
1357
|
return __async(this, null, function* () {
|
|
1344
|
-
|
|
1345
|
-
if (!this._authorize) {
|
|
1346
|
-
throw new Error("IO does not specify authorize during initialization.");
|
|
1347
|
-
}
|
|
1348
|
-
const ioAuthorize = this._getIOAuthorize(params);
|
|
1349
|
-
const user = params.user;
|
|
1350
|
-
const parsed = !!ioAuthorize ? ioAuthorize.user.parse(user) : user;
|
|
1351
|
-
const bytes = new TextEncoder().encode(JSON.stringify(parsed)).length;
|
|
1352
|
-
if (bytes > MAX_USER_SIZE_BYTES) {
|
|
1353
|
-
throw new Error(
|
|
1354
|
-
`createToken called with large payload. User must be at most 512 bytes. Current size: ${bytes.toLocaleString()}`
|
|
1355
|
-
);
|
|
1356
|
-
}
|
|
1357
|
-
if (this._platform._createToken) return yield this._platform._createToken(params);
|
|
1358
|
-
const secret = (_a = ioAuthorize == null ? void 0 : ioAuthorize.secret) != null ? _a : null;
|
|
1359
|
-
if (!secret) throw new Error("`authorize` was specified without a valid secret");
|
|
1360
|
-
return yield authorize({ platform: this._platform, secret }).encode(params);
|
|
1358
|
+
return yield this._io.createToken(params);
|
|
1361
1359
|
});
|
|
1362
1360
|
}
|
|
1363
|
-
_getIOAuthorize(options) {
|
|
1364
|
-
if (typeof this._authorize === "function") return this._authorize(options);
|
|
1365
|
-
return this._authorize;
|
|
1366
|
-
}
|
|
1367
1361
|
_getListeners() {
|
|
1368
1362
|
return this._listeners;
|
|
1369
1363
|
}
|
|
@@ -1378,9 +1372,15 @@ var PluvIO = class {
|
|
|
1378
1372
|
this.version = version;
|
|
1379
1373
|
this._authorize = null;
|
|
1380
1374
|
this._context = {};
|
|
1381
|
-
const { authorize: authorize2, context, crdt = import_crdt3.noop, debug = false, platform } = options;
|
|
1375
|
+
const { authorize: authorize2, context, crdt = import_crdt3.noop, debug = false, limits, platform } = options;
|
|
1382
1376
|
this._crdt = crdt;
|
|
1383
1377
|
this._debug = debug;
|
|
1378
|
+
this._limits = __spreadValues({
|
|
1379
|
+
presenceMaxSize: MAX_PRESENCE_SIZE_BYTES,
|
|
1380
|
+
storageMaxSize: MAX_STORAGE_SIZE_BYTES,
|
|
1381
|
+
userIdMaxLength: MAX_USER_ID_LENGTH,
|
|
1382
|
+
userMaxSize: MAX_USER_SIZE_BYTES
|
|
1383
|
+
}, limits);
|
|
1384
1384
|
this._platform = platform;
|
|
1385
1385
|
if (authorize2) this._authorize = authorize2;
|
|
1386
1386
|
if (context) this._context = context;
|
|
@@ -1393,6 +1393,20 @@ var PluvIO = class {
|
|
|
1393
1393
|
var _a;
|
|
1394
1394
|
if (!this._authorize) throw new Error("IO does not specify authorize during initialization.");
|
|
1395
1395
|
const ioAuthorize = this._getIOAuthorize(params);
|
|
1396
|
+
const user = params.user;
|
|
1397
|
+
const parsed = !!ioAuthorize ? ioAuthorize.user.parse(user) : user;
|
|
1398
|
+
if (!!this._limits.userIdMaxLength && user.id.length > this._limits.userIdMaxLength) {
|
|
1399
|
+
throw new Error(
|
|
1400
|
+
`createToken was called with a long user id. User ID must be at most 128 characters. Current length: ${user.id.length.toLocaleString()}`
|
|
1401
|
+
);
|
|
1402
|
+
}
|
|
1403
|
+
const bytes = new TextEncoder().encode(JSON.stringify(parsed)).length;
|
|
1404
|
+
if (!!this._limits.userMaxSize && bytes > this._limits.userMaxSize) {
|
|
1405
|
+
throw new Error(
|
|
1406
|
+
`createToken called with large payload. User must be at most 512 bytes. Current size: ${bytes.toLocaleString()}`
|
|
1407
|
+
);
|
|
1408
|
+
}
|
|
1409
|
+
if (this._platform._createToken) return yield this._platform._createToken(params);
|
|
1396
1410
|
const secret = (_a = ioAuthorize == null ? void 0 : ioAuthorize.secret) != null ? _a : null;
|
|
1397
1411
|
if (!secret) throw new Error("`authorize` was specified without a valid secret");
|
|
1398
1412
|
return yield authorize({ platform: this._platform, secret }).encode(params);
|
|
@@ -1415,6 +1429,8 @@ var PluvIO = class {
|
|
|
1415
1429
|
context: this._context,
|
|
1416
1430
|
crdt: this._crdt,
|
|
1417
1431
|
debug: this._debug,
|
|
1432
|
+
io: this,
|
|
1433
|
+
limits: this._limits,
|
|
1418
1434
|
platform: this._platform
|
|
1419
1435
|
}));
|
|
1420
1436
|
}
|
|
@@ -1428,12 +1444,13 @@ var PluvIO = class {
|
|
|
1428
1444
|
|
|
1429
1445
|
// src/createIO.ts
|
|
1430
1446
|
var createIO = (params) => {
|
|
1431
|
-
const { authorize: authorize2, context, crdt, debug, platform } = params;
|
|
1447
|
+
const { authorize: authorize2, context, crdt, debug, limits, platform } = params;
|
|
1432
1448
|
return new PluvIO({
|
|
1433
1449
|
authorize: authorize2,
|
|
1434
1450
|
context,
|
|
1435
1451
|
crdt,
|
|
1436
1452
|
debug,
|
|
1453
|
+
limits,
|
|
1437
1454
|
platform
|
|
1438
1455
|
});
|
|
1439
1456
|
};
|
package/dist/index.mjs
CHANGED
|
@@ -357,6 +357,8 @@ import colors from "kleur";
|
|
|
357
357
|
// src/constants.ts
|
|
358
358
|
var GARBAGE_COLLECT_INTERVAL_MS = 6e4;
|
|
359
359
|
var MAX_PRESENCE_SIZE_BYTES = 512;
|
|
360
|
+
var MAX_STORAGE_SIZE_BYTES = 31457280;
|
|
361
|
+
var MAX_USER_ID_LENGTH = 128;
|
|
360
362
|
var MAX_USER_SIZE_BYTES = 512;
|
|
361
363
|
var PING_TIMEOUT_MS = 3e4;
|
|
362
364
|
|
|
@@ -1097,7 +1099,7 @@ var pickBy = (obj, by) => {
|
|
|
1097
1099
|
};
|
|
1098
1100
|
|
|
1099
1101
|
// src/version.generated.ts
|
|
1100
|
-
var version = "0.
|
|
1102
|
+
var version = "0.44.0";
|
|
1101
1103
|
|
|
1102
1104
|
// src/PluvServer.ts
|
|
1103
1105
|
var PluvServer = class {
|
|
@@ -1148,18 +1150,22 @@ var PluvServer = class {
|
|
|
1148
1150
|
update
|
|
1149
1151
|
];
|
|
1150
1152
|
if (updates.some((_update) => !!_update)) {
|
|
1151
|
-
const
|
|
1152
|
-
yield this._platform.persistence.setStorageState(room,
|
|
1153
|
+
const encodedState2 = doc.batchApplyEncodedState({ updates }).getEncodedState();
|
|
1154
|
+
yield this._platform.persistence.setStorageState(room, encodedState2);
|
|
1153
1155
|
this._getListeners().onStorageUpdated({
|
|
1154
1156
|
context,
|
|
1155
|
-
encodedState,
|
|
1157
|
+
encodedState: encodedState2,
|
|
1156
1158
|
room,
|
|
1157
1159
|
user: session == null ? void 0 : session.user,
|
|
1158
1160
|
webSocket: session == null ? void 0 : session.webSocket.webSocket
|
|
1159
1161
|
});
|
|
1160
1162
|
}
|
|
1161
|
-
const
|
|
1162
|
-
|
|
1163
|
+
const encodedState = (_b = yield this._platform.persistence.getStorageState(room)) != null ? _b : doc.getEncodedState();
|
|
1164
|
+
const storageSize = new TextEncoder().encode(encodedState).length;
|
|
1165
|
+
if (!!this._limits.storageMaxSize && storageSize > this._limits.storageMaxSize) {
|
|
1166
|
+
throw new Error("Storage has exceeded the size limit");
|
|
1167
|
+
}
|
|
1168
|
+
return { $storageReceived: { state: encodedState } };
|
|
1163
1169
|
})),
|
|
1164
1170
|
$ping: this._procedure.self((data, { session }) => {
|
|
1165
1171
|
if (!session) return {};
|
|
@@ -1179,7 +1185,7 @@ var PluvServer = class {
|
|
|
1179
1185
|
const cleanedPatch = pickBy(presence != null ? presence : {}, (value) => typeof value !== "undefined");
|
|
1180
1186
|
const updated = Object.assign(/* @__PURE__ */ Object.create(null), session.presence, cleanedPatch);
|
|
1181
1187
|
const bytes = new TextEncoder().encode(JSON.stringify(updated)).length;
|
|
1182
|
-
if (bytes >
|
|
1188
|
+
if (!!this._limits.presenceMaxSize && bytes > this._limits.presenceMaxSize) {
|
|
1183
1189
|
throw new Error(
|
|
1184
1190
|
`Large presence. Presence must be at most 512 bytes. Current size: ${bytes.toLocaleString()}`
|
|
1185
1191
|
);
|
|
@@ -1199,6 +1205,10 @@ var PluvServer = class {
|
|
|
1199
1205
|
if (origin === "$initialized" && Object.keys(doc.toJson()).length) return {};
|
|
1200
1206
|
const updated = update === null ? doc : doc.applyEncodedState({ update });
|
|
1201
1207
|
const encodedState = updated.getEncodedState();
|
|
1208
|
+
const storageSize = new TextEncoder().encode(encodedState).length;
|
|
1209
|
+
if (!!this._limits.storageMaxSize && storageSize > this._limits.storageMaxSize) {
|
|
1210
|
+
throw new Error("Storage has exceeded the size limit");
|
|
1211
|
+
}
|
|
1202
1212
|
this._platform.persistence.setStorageState(room, encodedState).then(() => {
|
|
1203
1213
|
this._getListeners().onStorageUpdated({
|
|
1204
1214
|
context,
|
|
@@ -1217,6 +1227,8 @@ var PluvServer = class {
|
|
|
1217
1227
|
crdt = noop2,
|
|
1218
1228
|
debug = false,
|
|
1219
1229
|
getInitialStorage,
|
|
1230
|
+
io,
|
|
1231
|
+
limits,
|
|
1220
1232
|
platform,
|
|
1221
1233
|
router = new PluvRouter({})
|
|
1222
1234
|
} = options;
|
|
@@ -1224,6 +1236,8 @@ var PluvServer = class {
|
|
|
1224
1236
|
platform.validateConfig(options);
|
|
1225
1237
|
this._crdt = crdt;
|
|
1226
1238
|
this._debug = debug;
|
|
1239
|
+
this._io = io;
|
|
1240
|
+
this._limits = limits;
|
|
1227
1241
|
this._platform = platform;
|
|
1228
1242
|
this._router = router ? PluvRouter.merge(this._baseRouter, router) : this._baseRouter;
|
|
1229
1243
|
if (authorize2) this._authorize = authorize2;
|
|
@@ -1265,7 +1279,7 @@ var PluvServer = class {
|
|
|
1265
1279
|
if (this._platform._config.handleMode !== "io") {
|
|
1266
1280
|
throw new Error(`\`createRoom\` is unsupported for \`${this._platform._name}\``);
|
|
1267
1281
|
}
|
|
1268
|
-
if (!/^[a-z0-9]
|
|
1282
|
+
if (!/^[a-z0-9](?:[a-z0-9-_]*[a-z0-9])?$/i.test(room)) throw new Error("Unsupported room name");
|
|
1269
1283
|
const roomContext = platformRoomContext;
|
|
1270
1284
|
const context = typeof this._context === "function" ? this._context(roomContext) : this._context;
|
|
1271
1285
|
const newRoom = new IORoom(room, __spreadProps(__spreadValues({}, !!_meta ? { _meta } : {}), {
|
|
@@ -1299,29 +1313,9 @@ var PluvServer = class {
|
|
|
1299
1313
|
}
|
|
1300
1314
|
createToken(params) {
|
|
1301
1315
|
return __async(this, null, function* () {
|
|
1302
|
-
|
|
1303
|
-
if (!this._authorize) {
|
|
1304
|
-
throw new Error("IO does not specify authorize during initialization.");
|
|
1305
|
-
}
|
|
1306
|
-
const ioAuthorize = this._getIOAuthorize(params);
|
|
1307
|
-
const user = params.user;
|
|
1308
|
-
const parsed = !!ioAuthorize ? ioAuthorize.user.parse(user) : user;
|
|
1309
|
-
const bytes = new TextEncoder().encode(JSON.stringify(parsed)).length;
|
|
1310
|
-
if (bytes > MAX_USER_SIZE_BYTES) {
|
|
1311
|
-
throw new Error(
|
|
1312
|
-
`createToken called with large payload. User must be at most 512 bytes. Current size: ${bytes.toLocaleString()}`
|
|
1313
|
-
);
|
|
1314
|
-
}
|
|
1315
|
-
if (this._platform._createToken) return yield this._platform._createToken(params);
|
|
1316
|
-
const secret = (_a = ioAuthorize == null ? void 0 : ioAuthorize.secret) != null ? _a : null;
|
|
1317
|
-
if (!secret) throw new Error("`authorize` was specified without a valid secret");
|
|
1318
|
-
return yield authorize({ platform: this._platform, secret }).encode(params);
|
|
1316
|
+
return yield this._io.createToken(params);
|
|
1319
1317
|
});
|
|
1320
1318
|
}
|
|
1321
|
-
_getIOAuthorize(options) {
|
|
1322
|
-
if (typeof this._authorize === "function") return this._authorize(options);
|
|
1323
|
-
return this._authorize;
|
|
1324
|
-
}
|
|
1325
1319
|
_getListeners() {
|
|
1326
1320
|
return this._listeners;
|
|
1327
1321
|
}
|
|
@@ -1336,9 +1330,15 @@ var PluvIO = class {
|
|
|
1336
1330
|
this.version = version;
|
|
1337
1331
|
this._authorize = null;
|
|
1338
1332
|
this._context = {};
|
|
1339
|
-
const { authorize: authorize2, context, crdt = noop3, debug = false, platform } = options;
|
|
1333
|
+
const { authorize: authorize2, context, crdt = noop3, debug = false, limits, platform } = options;
|
|
1340
1334
|
this._crdt = crdt;
|
|
1341
1335
|
this._debug = debug;
|
|
1336
|
+
this._limits = __spreadValues({
|
|
1337
|
+
presenceMaxSize: MAX_PRESENCE_SIZE_BYTES,
|
|
1338
|
+
storageMaxSize: MAX_STORAGE_SIZE_BYTES,
|
|
1339
|
+
userIdMaxLength: MAX_USER_ID_LENGTH,
|
|
1340
|
+
userMaxSize: MAX_USER_SIZE_BYTES
|
|
1341
|
+
}, limits);
|
|
1342
1342
|
this._platform = platform;
|
|
1343
1343
|
if (authorize2) this._authorize = authorize2;
|
|
1344
1344
|
if (context) this._context = context;
|
|
@@ -1351,6 +1351,20 @@ var PluvIO = class {
|
|
|
1351
1351
|
var _a;
|
|
1352
1352
|
if (!this._authorize) throw new Error("IO does not specify authorize during initialization.");
|
|
1353
1353
|
const ioAuthorize = this._getIOAuthorize(params);
|
|
1354
|
+
const user = params.user;
|
|
1355
|
+
const parsed = !!ioAuthorize ? ioAuthorize.user.parse(user) : user;
|
|
1356
|
+
if (!!this._limits.userIdMaxLength && user.id.length > this._limits.userIdMaxLength) {
|
|
1357
|
+
throw new Error(
|
|
1358
|
+
`createToken was called with a long user id. User ID must be at most 128 characters. Current length: ${user.id.length.toLocaleString()}`
|
|
1359
|
+
);
|
|
1360
|
+
}
|
|
1361
|
+
const bytes = new TextEncoder().encode(JSON.stringify(parsed)).length;
|
|
1362
|
+
if (!!this._limits.userMaxSize && bytes > this._limits.userMaxSize) {
|
|
1363
|
+
throw new Error(
|
|
1364
|
+
`createToken called with large payload. User must be at most 512 bytes. Current size: ${bytes.toLocaleString()}`
|
|
1365
|
+
);
|
|
1366
|
+
}
|
|
1367
|
+
if (this._platform._createToken) return yield this._platform._createToken(params);
|
|
1354
1368
|
const secret = (_a = ioAuthorize == null ? void 0 : ioAuthorize.secret) != null ? _a : null;
|
|
1355
1369
|
if (!secret) throw new Error("`authorize` was specified without a valid secret");
|
|
1356
1370
|
return yield authorize({ platform: this._platform, secret }).encode(params);
|
|
@@ -1373,6 +1387,8 @@ var PluvIO = class {
|
|
|
1373
1387
|
context: this._context,
|
|
1374
1388
|
crdt: this._crdt,
|
|
1375
1389
|
debug: this._debug,
|
|
1390
|
+
io: this,
|
|
1391
|
+
limits: this._limits,
|
|
1376
1392
|
platform: this._platform
|
|
1377
1393
|
}));
|
|
1378
1394
|
}
|
|
@@ -1386,12 +1402,13 @@ var PluvIO = class {
|
|
|
1386
1402
|
|
|
1387
1403
|
// src/createIO.ts
|
|
1388
1404
|
var createIO = (params) => {
|
|
1389
|
-
const { authorize: authorize2, context, crdt, debug, platform } = params;
|
|
1405
|
+
const { authorize: authorize2, context, crdt, debug, limits, platform } = params;
|
|
1390
1406
|
return new PluvIO({
|
|
1391
1407
|
authorize: authorize2,
|
|
1392
1408
|
context,
|
|
1393
1409
|
crdt,
|
|
1394
1410
|
debug,
|
|
1411
|
+
limits,
|
|
1395
1412
|
platform
|
|
1396
1413
|
});
|
|
1397
1414
|
};
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@pluv/io",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.44.0",
|
|
4
4
|
"description": "@pluv/io server-side websocket manager",
|
|
5
5
|
"author": "leedavidcs",
|
|
6
6
|
"license": "MIT",
|
|
@@ -21,16 +21,16 @@
|
|
|
21
21
|
"jose": "^5.10.0",
|
|
22
22
|
"kleur": "^4.1.5",
|
|
23
23
|
"wonka": "^6.3.5",
|
|
24
|
-
"@pluv/crdt": "^0.
|
|
25
|
-
"@pluv/types": "^0.
|
|
24
|
+
"@pluv/crdt": "^0.44.0",
|
|
25
|
+
"@pluv/types": "^0.44.0"
|
|
26
26
|
},
|
|
27
27
|
"devDependencies": {
|
|
28
28
|
"eslint": "^9.25.1",
|
|
29
29
|
"genversion": "^3.2.0",
|
|
30
30
|
"tsup": "^8.4.0",
|
|
31
31
|
"typescript": "^5.8.3",
|
|
32
|
-
"@pluv/tsconfig": "^0.
|
|
33
|
-
"eslint-config-pluv": "^0.
|
|
32
|
+
"@pluv/tsconfig": "^0.44.0",
|
|
33
|
+
"eslint-config-pluv": "^0.44.0"
|
|
34
34
|
},
|
|
35
35
|
"scripts": {
|
|
36
36
|
"build": "pnpm run version && tsup src/index.ts --format esm,cjs --dts",
|
package/src/PluvIO.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import type { AbstractCrdtDocFactory } from "@pluv/crdt";
|
|
2
2
|
import { noop } from "@pluv/crdt";
|
|
3
|
-
import type { IOAuthorize, InferIOAuthorizeUser } from "@pluv/types";
|
|
3
|
+
import type { BaseUser, IOAuthorize, InferIOAuthorizeUser } from "@pluv/types";
|
|
4
4
|
import type { AbstractPlatform, InferInitContextType } from "./AbstractPlatform";
|
|
5
5
|
import type { WebSocketRegisterConfig } from "./IORoom";
|
|
6
6
|
import { PluvProcedure } from "./PluvProcedure";
|
|
@@ -9,11 +9,13 @@ import { PluvRouter } from "./PluvRouter";
|
|
|
9
9
|
import { PluvServer, PluvServerConfig } from "./PluvServer";
|
|
10
10
|
import type { JWTEncodeParams } from "./authorize";
|
|
11
11
|
import { authorize } from "./authorize";
|
|
12
|
+
import { MAX_PRESENCE_SIZE_BYTES, MAX_STORAGE_SIZE_BYTES, MAX_USER_ID_LENGTH, MAX_USER_SIZE_BYTES } from "./constants";
|
|
12
13
|
import type {
|
|
13
14
|
CrdtLibraryType,
|
|
14
15
|
GetInitialStorageFn,
|
|
15
16
|
PluvContext,
|
|
16
17
|
PluvIOAuthorize,
|
|
18
|
+
PluvIOLimits,
|
|
17
19
|
PluvIOListeners,
|
|
18
20
|
PluvIORouter,
|
|
19
21
|
ResolvedPluvIOAuthorize,
|
|
@@ -29,6 +31,7 @@ export type PluvIOConfig<
|
|
|
29
31
|
context?: PluvContext<TPlatform, TContext>;
|
|
30
32
|
crdt?: CrdtLibraryType;
|
|
31
33
|
debug?: boolean;
|
|
34
|
+
limits?: PluvIOLimits;
|
|
32
35
|
platform: TPlatform;
|
|
33
36
|
};
|
|
34
37
|
|
|
@@ -69,6 +72,7 @@ export class PluvIO<
|
|
|
69
72
|
private readonly _context: PluvContext<TPlatform, TContext> = {} as PluvContext<TPlatform, TContext>;
|
|
70
73
|
private readonly _crdt: { doc: (value: any) => AbstractCrdtDocFactory<any> };
|
|
71
74
|
private readonly _debug: boolean;
|
|
75
|
+
private readonly _limits: PluvIOLimits;
|
|
72
76
|
private readonly _platform: TPlatform;
|
|
73
77
|
|
|
74
78
|
public get procedure(): PluvProcedure<TPlatform, TAuthorize, TContext, {}, {}> {
|
|
@@ -76,10 +80,17 @@ export class PluvIO<
|
|
|
76
80
|
}
|
|
77
81
|
|
|
78
82
|
constructor(options: PluvIOConfig<TPlatform, TAuthorize, TContext>) {
|
|
79
|
-
const { authorize, context, crdt = noop, debug = false, platform } = options;
|
|
83
|
+
const { authorize, context, crdt = noop, debug = false, limits, platform } = options;
|
|
80
84
|
|
|
81
85
|
this._crdt = crdt;
|
|
82
86
|
this._debug = debug;
|
|
87
|
+
this._limits = {
|
|
88
|
+
presenceMaxSize: MAX_PRESENCE_SIZE_BYTES,
|
|
89
|
+
storageMaxSize: MAX_STORAGE_SIZE_BYTES,
|
|
90
|
+
userIdMaxLength: MAX_USER_ID_LENGTH,
|
|
91
|
+
userMaxSize: MAX_USER_SIZE_BYTES,
|
|
92
|
+
...limits,
|
|
93
|
+
};
|
|
83
94
|
this._platform = platform;
|
|
84
95
|
|
|
85
96
|
if (authorize) this._authorize = authorize;
|
|
@@ -90,6 +101,31 @@ export class PluvIO<
|
|
|
90
101
|
if (!this._authorize) throw new Error("IO does not specify authorize during initialization.");
|
|
91
102
|
|
|
92
103
|
const ioAuthorize = this._getIOAuthorize(params);
|
|
104
|
+
const user = params.user as BaseUser;
|
|
105
|
+
const parsed = !!ioAuthorize ? ioAuthorize.user.parse(user) : user;
|
|
106
|
+
|
|
107
|
+
if (!!this._limits.userIdMaxLength && user.id.length > this._limits.userIdMaxLength) {
|
|
108
|
+
throw new Error(
|
|
109
|
+
`createToken was called with a long user id. User ID must be at most 128 characters. Current length: ${user.id.length.toLocaleString()}`,
|
|
110
|
+
);
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
const bytes = new TextEncoder().encode(JSON.stringify(parsed)).length;
|
|
114
|
+
|
|
115
|
+
if (!!this._limits.userMaxSize && bytes > this._limits.userMaxSize) {
|
|
116
|
+
throw new Error(
|
|
117
|
+
`createToken called with large payload. User must be at most 512 bytes. Current size: ${bytes.toLocaleString()}`,
|
|
118
|
+
);
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
/**
|
|
122
|
+
* !HACK
|
|
123
|
+
* @description Allow the platform to overwrite this behavior as needed. This is introduced
|
|
124
|
+
* to support platformPluv
|
|
125
|
+
* @date December 15, 2024
|
|
126
|
+
*/
|
|
127
|
+
if (this._platform._createToken) return await this._platform._createToken(params as any);
|
|
128
|
+
|
|
93
129
|
const secret = ioAuthorize?.secret ?? null;
|
|
94
130
|
|
|
95
131
|
if (!secret) throw new Error("`authorize` was specified without a valid secret");
|
|
@@ -129,6 +165,8 @@ export class PluvIO<
|
|
|
129
165
|
context: this._context,
|
|
130
166
|
crdt: this._crdt,
|
|
131
167
|
debug: this._debug,
|
|
168
|
+
io: this as PluvIO<TPlatform, TAuthorize, TContext>,
|
|
169
|
+
limits: this._limits,
|
|
132
170
|
platform: this._platform,
|
|
133
171
|
} as PluvServerConfig<TPlatform, TAuthorize, TContext, TEvents>);
|
|
134
172
|
}
|
package/src/PluvServer.ts
CHANGED
|
@@ -1,23 +1,23 @@
|
|
|
1
1
|
import type { AbstractCrdtDocFactory } from "@pluv/crdt";
|
|
2
2
|
import { noop } from "@pluv/crdt";
|
|
3
|
-
import type {
|
|
3
|
+
import type { 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
|
-
import type { IORoomListeners
|
|
6
|
+
import type { IORoomListeners } from "./IORoom";
|
|
7
7
|
import { IORoom } from "./IORoom";
|
|
8
|
+
import type { PluvIO } from "./PluvIO";
|
|
8
9
|
import { PluvProcedure } from "./PluvProcedure";
|
|
9
10
|
import type { PluvRouterEventConfig } from "./PluvRouter";
|
|
10
11
|
import { PluvRouter } from "./PluvRouter";
|
|
11
12
|
import type { JWTEncodeParams } from "./authorize";
|
|
12
|
-
import {
|
|
13
|
-
import { MAX_PRESENCE_SIZE_BYTES, MAX_USER_SIZE_BYTES, PING_TIMEOUT_MS } from "./constants";
|
|
13
|
+
import { PING_TIMEOUT_MS } from "./constants";
|
|
14
14
|
import type {
|
|
15
15
|
BasePluvIOListeners,
|
|
16
16
|
GetInitialStorageFn,
|
|
17
17
|
PluvContext,
|
|
18
18
|
PluvIOAuthorize,
|
|
19
|
+
PluvIOLimits,
|
|
19
20
|
PluvIOListeners,
|
|
20
|
-
ResolvedPluvIOAuthorize,
|
|
21
21
|
} from "./types";
|
|
22
22
|
import { pickBy } from "./utils";
|
|
23
23
|
import { __PLUV_VERSION } from "./version";
|
|
@@ -38,6 +38,8 @@ export type PluvServerConfig<
|
|
|
38
38
|
crdt?: { doc: (value: any) => AbstractCrdtDocFactory<any> };
|
|
39
39
|
debug?: boolean;
|
|
40
40
|
getInitialStorage?: GetInitialStorageFn<TContext>;
|
|
41
|
+
limits: PluvIOLimits;
|
|
42
|
+
io: PluvIO<TPlatform, TAuthorize, TContext>;
|
|
41
43
|
platform: TPlatform;
|
|
42
44
|
router?: PluvRouter<TPlatform, TAuthorize, TContext, TEvents>;
|
|
43
45
|
};
|
|
@@ -132,7 +134,7 @@ export class PluvServer<
|
|
|
132
134
|
];
|
|
133
135
|
|
|
134
136
|
if (updates.some((_update) => !!_update)) {
|
|
135
|
-
const encodedState = doc.batchApplyEncodedState(updates).getEncodedState();
|
|
137
|
+
const encodedState = doc.batchApplyEncodedState({ updates }).getEncodedState();
|
|
136
138
|
|
|
137
139
|
await this._platform.persistence.setStorageState(room, encodedState);
|
|
138
140
|
|
|
@@ -145,9 +147,14 @@ export class PluvServer<
|
|
|
145
147
|
});
|
|
146
148
|
}
|
|
147
149
|
|
|
148
|
-
const
|
|
150
|
+
const encodedState = (await this._platform.persistence.getStorageState(room)) ?? doc.getEncodedState();
|
|
151
|
+
const storageSize = new TextEncoder().encode(encodedState).length;
|
|
149
152
|
|
|
150
|
-
|
|
153
|
+
if (!!this._limits.storageMaxSize && storageSize > this._limits.storageMaxSize) {
|
|
154
|
+
throw new Error("Storage has exceeded the size limit");
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
return { $storageReceived: { state: encodedState } };
|
|
151
158
|
}),
|
|
152
159
|
$ping: this._procedure.self((data, { session }) => {
|
|
153
160
|
if (!session) return {};
|
|
@@ -175,7 +182,7 @@ export class PluvServer<
|
|
|
175
182
|
const updated = Object.assign(Object.create(null), session.presence, cleanedPatch);
|
|
176
183
|
const bytes = new TextEncoder().encode(JSON.stringify(updated)).length;
|
|
177
184
|
|
|
178
|
-
if (bytes >
|
|
185
|
+
if (!!this._limits.presenceMaxSize && bytes > this._limits.presenceMaxSize) {
|
|
179
186
|
throw new Error(
|
|
180
187
|
`Large presence. Presence must be at most 512 bytes. Current size: ${bytes.toLocaleString()}`,
|
|
181
188
|
);
|
|
@@ -198,6 +205,11 @@ export class PluvServer<
|
|
|
198
205
|
|
|
199
206
|
const updated = update === null ? doc : doc.applyEncodedState({ update });
|
|
200
207
|
const encodedState = updated.getEncodedState();
|
|
208
|
+
const storageSize = new TextEncoder().encode(encodedState).length;
|
|
209
|
+
|
|
210
|
+
if (!!this._limits.storageMaxSize && storageSize > this._limits.storageMaxSize) {
|
|
211
|
+
throw new Error("Storage has exceeded the size limit");
|
|
212
|
+
}
|
|
201
213
|
|
|
202
214
|
this._platform.persistence.setStorageState(room, encodedState).then(() => {
|
|
203
215
|
this._getListeners().onStorageUpdated({
|
|
@@ -214,6 +226,8 @@ export class PluvServer<
|
|
|
214
226
|
private readonly _crdt: { doc: (value: any) => AbstractCrdtDocFactory<any> };
|
|
215
227
|
private readonly _debug: boolean;
|
|
216
228
|
private readonly _getInitialStorage: GetInitialStorageFn<TContext> | null = null;
|
|
229
|
+
private readonly _io: PluvIO<TPlatform, TAuthorize, TContext>;
|
|
230
|
+
private readonly _limits: PluvIOLimits;
|
|
217
231
|
private readonly _platform: TPlatform;
|
|
218
232
|
private readonly _router: PluvRouter<TPlatform, TAuthorize, TContext, TEvents>;
|
|
219
233
|
|
|
@@ -255,6 +269,8 @@ export class PluvServer<
|
|
|
255
269
|
crdt = noop,
|
|
256
270
|
debug = false,
|
|
257
271
|
getInitialStorage,
|
|
272
|
+
io,
|
|
273
|
+
limits,
|
|
258
274
|
platform,
|
|
259
275
|
router = new PluvRouter<TPlatform, TAuthorize, TContext, TEvents>({} as TEvents),
|
|
260
276
|
} = options;
|
|
@@ -266,6 +282,8 @@ export class PluvServer<
|
|
|
266
282
|
|
|
267
283
|
this._crdt = crdt;
|
|
268
284
|
this._debug = debug;
|
|
285
|
+
this._io = io;
|
|
286
|
+
this._limits = limits;
|
|
269
287
|
this._platform = platform;
|
|
270
288
|
this._router = (router ? PluvRouter.merge(this._baseRouter, router) : this._baseRouter) as PluvRouter<
|
|
271
289
|
TPlatform,
|
|
@@ -302,7 +320,7 @@ export class PluvServer<
|
|
|
302
320
|
throw new Error(`\`createRoom\` is unsupported for \`${this._platform._name}\``);
|
|
303
321
|
}
|
|
304
322
|
|
|
305
|
-
if (!/^[a-z0-9]
|
|
323
|
+
if (!/^[a-z0-9](?:[a-z0-9-_]*[a-z0-9])?$/i.test(room)) throw new Error("Unsupported room name");
|
|
306
324
|
|
|
307
325
|
const roomContext = platformRoomContext as InferRoomContextType<TPlatform>;
|
|
308
326
|
const context: TContext = typeof this._context === "function" ? this._context(roomContext) : this._context;
|
|
@@ -345,41 +363,7 @@ export class PluvServer<
|
|
|
345
363
|
public async createToken(
|
|
346
364
|
params: JWTEncodeParams<InferIOAuthorizeUser<InferIOAuthorize<this>>, TPlatform>,
|
|
347
365
|
): Promise<string> {
|
|
348
|
-
|
|
349
|
-
throw new Error("IO does not specify authorize during initialization.");
|
|
350
|
-
}
|
|
351
|
-
|
|
352
|
-
const ioAuthorize = this._getIOAuthorize(params);
|
|
353
|
-
const user = params.user as BaseUser;
|
|
354
|
-
const parsed = !!ioAuthorize ? ioAuthorize.user.parse(user) : user;
|
|
355
|
-
|
|
356
|
-
const bytes = new TextEncoder().encode(JSON.stringify(parsed)).length;
|
|
357
|
-
|
|
358
|
-
if (bytes > MAX_USER_SIZE_BYTES) {
|
|
359
|
-
throw new Error(
|
|
360
|
-
`createToken called with large payload. User must be at most 512 bytes. Current size: ${bytes.toLocaleString()}`,
|
|
361
|
-
);
|
|
362
|
-
}
|
|
363
|
-
|
|
364
|
-
/**
|
|
365
|
-
* !HACK
|
|
366
|
-
* @description Allow the platform to overwrite this behavior as needed. This is introduced
|
|
367
|
-
* to support platformPluv
|
|
368
|
-
* @date December 15, 2024
|
|
369
|
-
*/
|
|
370
|
-
if (this._platform._createToken) return await this._platform._createToken(params as any);
|
|
371
|
-
|
|
372
|
-
const secret = ioAuthorize?.secret ?? null;
|
|
373
|
-
|
|
374
|
-
if (!secret) throw new Error("`authorize` was specified without a valid secret");
|
|
375
|
-
|
|
376
|
-
return await authorize({ platform: this._platform, secret }).encode(params as JWTEncodeParams<any, TPlatform>);
|
|
377
|
-
}
|
|
378
|
-
|
|
379
|
-
private _getIOAuthorize(options: WebSocketRegisterConfig<TPlatform>): ResolvedPluvIOAuthorize<any, any> | null {
|
|
380
|
-
if (typeof this._authorize === "function") return this._authorize(options);
|
|
381
|
-
|
|
382
|
-
return this._authorize as ResolvedPluvIOAuthorize<any, any> | null;
|
|
366
|
+
return await this._io.createToken(params);
|
|
383
367
|
}
|
|
384
368
|
|
|
385
369
|
private _getListeners(): BasePluvIOListeners<TPlatform, TAuthorize, TContext, TEvents> {
|
package/src/constants.ts
CHANGED
|
@@ -1,4 +1,6 @@
|
|
|
1
1
|
export const GARBAGE_COLLECT_INTERVAL_MS = 60_000;
|
|
2
2
|
export const MAX_PRESENCE_SIZE_BYTES = 512;
|
|
3
|
+
export const MAX_STORAGE_SIZE_BYTES = 31_457_280;
|
|
4
|
+
export const MAX_USER_ID_LENGTH = 128;
|
|
3
5
|
export const MAX_USER_SIZE_BYTES = 512;
|
|
4
6
|
export const PING_TIMEOUT_MS = 30_000;
|
package/src/createIO.ts
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import type { BaseUser } from "@pluv/types";
|
|
2
2
|
import type { AbstractPlatform, InferInitContextType } from "./AbstractPlatform";
|
|
3
3
|
import { PluvIO } from "./PluvIO";
|
|
4
|
-
import type { CrdtLibraryType, PluvContext, PluvIOAuthorize } from "./types";
|
|
4
|
+
import type { CrdtLibraryType, PluvContext, PluvIOAuthorize, PluvIOLimits } from "./types";
|
|
5
5
|
|
|
6
6
|
export type CreateIOParams<
|
|
7
7
|
TPlatform extends AbstractPlatform<any> = AbstractPlatform<any>,
|
|
@@ -12,6 +12,7 @@ export type CreateIOParams<
|
|
|
12
12
|
context?: PluvContext<TPlatform, TContext>;
|
|
13
13
|
crdt?: CrdtLibraryType;
|
|
14
14
|
debug?: boolean;
|
|
15
|
+
limits?: PluvIOLimits;
|
|
15
16
|
platform: TPlatform;
|
|
16
17
|
};
|
|
17
18
|
|
|
@@ -22,13 +23,14 @@ export const createIO = <
|
|
|
22
23
|
>(
|
|
23
24
|
params: CreateIOParams<TPlatform, TContext, TUser>,
|
|
24
25
|
): PluvIO<TPlatform, PluvIOAuthorize<TPlatform, TUser, InferInitContextType<TPlatform>>, TContext> => {
|
|
25
|
-
const { authorize, context, crdt, debug, platform } = params;
|
|
26
|
+
const { authorize, context, crdt, debug, limits, platform } = params;
|
|
26
27
|
|
|
27
28
|
return new PluvIO<TPlatform, PluvIOAuthorize<TPlatform, TUser, InferInitContextType<TPlatform>>, TContext>({
|
|
28
29
|
authorize,
|
|
29
30
|
context,
|
|
30
31
|
crdt,
|
|
31
32
|
debug,
|
|
33
|
+
limits,
|
|
32
34
|
platform,
|
|
33
35
|
});
|
|
34
36
|
};
|
package/src/index.ts
CHANGED
package/src/types.ts
CHANGED
|
@@ -145,6 +145,25 @@ export type PluvIOAuthorize<
|
|
|
145
145
|
| (TUser extends BaseUser ? ResolvedPluvIOAuthorize<TPlatform, TUser> : null)
|
|
146
146
|
| ((context: TContext) => TUser extends BaseUser ? ResolvedPluvIOAuthorize<TPlatform, TUser> : null);
|
|
147
147
|
|
|
148
|
+
export interface PluvIOLimits {
|
|
149
|
+
/**
|
|
150
|
+
* @description Maximum size of presence object in bytes
|
|
151
|
+
*/
|
|
152
|
+
presenceMaxSize?: number | null;
|
|
153
|
+
/**
|
|
154
|
+
* @description Maximum size of storage state in bytes
|
|
155
|
+
*/
|
|
156
|
+
storageMaxSize?: number | null;
|
|
157
|
+
/**
|
|
158
|
+
* @description Maximum length of user id in characters
|
|
159
|
+
*/
|
|
160
|
+
userIdMaxLength?: number | null;
|
|
161
|
+
/**
|
|
162
|
+
* @description Maximum size of user object in bytes
|
|
163
|
+
*/
|
|
164
|
+
userMaxSize?: number | null;
|
|
165
|
+
}
|
|
166
|
+
|
|
148
167
|
export type BasePluvIOListeners<
|
|
149
168
|
TPlatform extends AbstractPlatform<any, any, any, any>,
|
|
150
169
|
TAuthorize extends PluvIOAuthorize<TPlatform, any, InferInitContextType<TPlatform>> | null,
|
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.44.0'
|