@pluv/client 0.42.0 → 0.43.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 +8 -8
- package/CHANGELOG.md +18 -0
- package/dist/index.d.mts +27 -10
- package/dist/index.d.ts +27 -10
- package/dist/index.js +28 -12
- package/dist/index.mjs +28 -12
- package/package.json +5 -5
- package/src/MockedRoom.ts +20 -16
- package/src/PluvClient.ts +23 -2
- package/src/PluvRoom.ts +6 -1
- package/src/UsersManager.ts +9 -7
- package/src/types.ts +7 -0
package/.turbo/turbo-build.log
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
|
|
2
|
-
> @pluv/client@0.
|
|
2
|
+
> @pluv/client@0.43.0 build /home/runner/work/pluv/pluv/packages/client
|
|
3
3
|
> tsup src/index.ts --format esm,cjs --dts
|
|
4
4
|
|
|
5
5
|
[34mCLI[39m Building entry: src/index.ts
|
|
@@ -8,11 +8,11 @@
|
|
|
8
8
|
[34mCLI[39m Target: es6
|
|
9
9
|
[34mESM[39m Build start
|
|
10
10
|
[34mCJS[39m Build start
|
|
11
|
-
[
|
|
12
|
-
[
|
|
13
|
-
[
|
|
14
|
-
[
|
|
11
|
+
[32mCJS[39m [1mdist/index.js [22m[32m57.65 KB[39m
|
|
12
|
+
[32mCJS[39m ⚡️ Build success in 115ms
|
|
13
|
+
[32mESM[39m [1mdist/index.mjs [22m[32m56.33 KB[39m
|
|
14
|
+
[32mESM[39m ⚡️ Build success in 116ms
|
|
15
15
|
[34mDTS[39m Build start
|
|
16
|
-
[32mDTS[39m ⚡️ Build success in
|
|
17
|
-
[32mDTS[39m [1mdist/index.d.mts [22m[
|
|
18
|
-
[32mDTS[39m [1mdist/index.d.ts [22m[
|
|
16
|
+
[32mDTS[39m ⚡️ Build success in 3550ms
|
|
17
|
+
[32mDTS[39m [1mdist/index.d.mts [22m[32m25.24 KB[39m
|
|
18
|
+
[32mDTS[39m [1mdist/index.d.ts [22m[32m25.24 KB[39m
|
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,23 @@
|
|
|
1
1
|
# @pluv/client
|
|
2
2
|
|
|
3
|
+
## 0.43.0
|
|
4
|
+
|
|
5
|
+
### Patch Changes
|
|
6
|
+
|
|
7
|
+
- 65d9172: Added configurable limits for client-side validation. These should only be updated if you control the server and the server limits have been changed.
|
|
8
|
+
|
|
9
|
+
```ts
|
|
10
|
+
// defaults
|
|
11
|
+
createClient({
|
|
12
|
+
limits: {
|
|
13
|
+
presenceMaxSize: 512,
|
|
14
|
+
},
|
|
15
|
+
});
|
|
16
|
+
```
|
|
17
|
+
|
|
18
|
+
- @pluv/crdt@0.43.0
|
|
19
|
+
- @pluv/types@0.43.0
|
|
20
|
+
|
|
3
21
|
## 0.42.0
|
|
4
22
|
|
|
5
23
|
### Patch Changes
|
package/dist/index.d.mts
CHANGED
|
@@ -84,6 +84,7 @@ type SubscriptionCallback<TIO extends IOLike, TPresence extends JsonObject, TSub
|
|
|
84
84
|
|
|
85
85
|
type UsersManagerConfig<TPresence extends JsonObject = {}> = {
|
|
86
86
|
initialPresence?: TPresence;
|
|
87
|
+
limits: PluvClientLimits;
|
|
87
88
|
presence?: InputZodLike<TPresence>;
|
|
88
89
|
};
|
|
89
90
|
|
|
@@ -130,6 +131,7 @@ type ReconnectTimeoutMs = number | ((params: ReconnectTimeoutMsParams) => number
|
|
|
130
131
|
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<{
|
|
131
132
|
addons?: readonly PluvRoomAddon<TIO, TMetadata, TPresence, TStorage>[];
|
|
132
133
|
debug?: boolean | PluvRoomDebug<TIO>;
|
|
134
|
+
limits: PluvClientLimits;
|
|
133
135
|
onAuthorizationFail?: (error: Error) => void;
|
|
134
136
|
metadata?: InputZodLike<TMetadata>;
|
|
135
137
|
publicKey?: PublicKey<TMetadata>;
|
|
@@ -144,6 +146,7 @@ declare class PluvRoom<TIO extends IOLike<any, any>, TMetadata extends JsonObjec
|
|
|
144
146
|
private readonly _debug;
|
|
145
147
|
private readonly _eventNotifier;
|
|
146
148
|
private readonly _intervals;
|
|
149
|
+
private readonly _limits;
|
|
147
150
|
private readonly _listeners;
|
|
148
151
|
private readonly _otherNotifier;
|
|
149
152
|
private readonly _publicKey;
|
|
@@ -235,6 +238,11 @@ declare class PluvRoom<TIO extends IOLike<any, any>, TMetadata extends JsonObjec
|
|
|
235
238
|
type PluvClientOptions<TIO extends IOLike<any, any>, TPresence extends JsonObject, TStorage extends Record<string, CrdtType<any, any>>, TMetadata extends JsonObject> = RoomEndpoints<TIO, TMetadata> & {
|
|
236
239
|
debug?: boolean;
|
|
237
240
|
initialStorage?: AbstractCrdtDocFactory<TStorage>;
|
|
241
|
+
/**
|
|
242
|
+
* @description Configurable limits defined for client-side validation. You should only set
|
|
243
|
+
* this if you control the server and have changed the limits there.
|
|
244
|
+
*/
|
|
245
|
+
limits?: PluvClientLimits;
|
|
238
246
|
metadata?: InputZodLike<TMetadata>;
|
|
239
247
|
presence?: InputZodLike<TPresence>;
|
|
240
248
|
publicKey?: PublicKey<TMetadata>;
|
|
@@ -255,6 +263,7 @@ declare class PluvClient<TIO extends IOLike<any, any>, TPresence extends JsonObj
|
|
|
255
263
|
private readonly _authEndpoint;
|
|
256
264
|
private readonly _debug;
|
|
257
265
|
private readonly _initialStorage?;
|
|
266
|
+
private readonly _limits;
|
|
258
267
|
private readonly _presence?;
|
|
259
268
|
private readonly _publicKey;
|
|
260
269
|
private readonly _rooms;
|
|
@@ -291,6 +300,12 @@ type MergeEventRecords<TEventRecords extends EventRecord<string, any>[], TRoot e
|
|
|
291
300
|
] ? MergeEventRecords<ITail, Omit<TRoot, keyof IHead> & {
|
|
292
301
|
[P in keyof IHead]: TRoot extends Record<P, any> ? TRoot[P] | IHead[P] : IHead[P];
|
|
293
302
|
}> : Id<TRoot>;
|
|
303
|
+
interface PluvClientLimits {
|
|
304
|
+
/**
|
|
305
|
+
* @description Maximum size of presence object in bytes
|
|
306
|
+
*/
|
|
307
|
+
presenceMaxSize?: number | null;
|
|
308
|
+
}
|
|
294
309
|
interface PublicKeyParams<TMetadata extends JsonObject> {
|
|
295
310
|
metadata: TMetadata;
|
|
296
311
|
}
|
|
@@ -368,19 +383,21 @@ type MockedRoomEvents<TIO extends IOLike> = Partial<{
|
|
|
368
383
|
}>;
|
|
369
384
|
type MockedRoomConfig<TIO extends IOLike, TPresence extends JsonObject = {}, TStorage extends Record<string, CrdtType<any, any>> = {}, TEvents extends PluvRouterEventConfig<TIO, TPresence, TStorage> = {}> = {
|
|
370
385
|
events?: MockedRoomEvents<MergeEvents<TEvents, TIO>>;
|
|
386
|
+
limits?: PluvClientLimits;
|
|
371
387
|
router?: PluvRouter<TIO, TPresence, TStorage, TEvents>;
|
|
372
|
-
} & Pick<CrdtManagerOptions<TStorage>, "initialStorage"> & UsersManagerConfig<TPresence>;
|
|
388
|
+
} & Pick<CrdtManagerOptions<TStorage>, "initialStorage"> & Omit<UsersManagerConfig<TPresence>, "limits">;
|
|
373
389
|
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> {
|
|
374
|
-
private _crdtManager;
|
|
375
|
-
private _crdtNotifier;
|
|
376
|
-
private _eventNotifier;
|
|
377
|
-
private _events?;
|
|
378
|
-
private
|
|
379
|
-
private
|
|
390
|
+
private readonly _crdtManager;
|
|
391
|
+
private readonly _crdtNotifier;
|
|
392
|
+
private readonly _eventNotifier;
|
|
393
|
+
private readonly _events?;
|
|
394
|
+
private readonly _limits;
|
|
395
|
+
private readonly _otherNotifier;
|
|
396
|
+
private readonly _router;
|
|
380
397
|
private _state;
|
|
381
|
-
private _stateNotifier;
|
|
382
|
-
private _subscriptions;
|
|
383
|
-
private _usersManager;
|
|
398
|
+
private readonly _stateNotifier;
|
|
399
|
+
private readonly _subscriptions;
|
|
400
|
+
private readonly _usersManager;
|
|
384
401
|
constructor(room: string, options: MockedRoomConfig<TIO, TPresence, TStorage, TEvents>);
|
|
385
402
|
get storageLoaded(): boolean;
|
|
386
403
|
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>; };
|
package/dist/index.d.ts
CHANGED
|
@@ -84,6 +84,7 @@ type SubscriptionCallback<TIO extends IOLike, TPresence extends JsonObject, TSub
|
|
|
84
84
|
|
|
85
85
|
type UsersManagerConfig<TPresence extends JsonObject = {}> = {
|
|
86
86
|
initialPresence?: TPresence;
|
|
87
|
+
limits: PluvClientLimits;
|
|
87
88
|
presence?: InputZodLike<TPresence>;
|
|
88
89
|
};
|
|
89
90
|
|
|
@@ -130,6 +131,7 @@ type ReconnectTimeoutMs = number | ((params: ReconnectTimeoutMsParams) => number
|
|
|
130
131
|
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<{
|
|
131
132
|
addons?: readonly PluvRoomAddon<TIO, TMetadata, TPresence, TStorage>[];
|
|
132
133
|
debug?: boolean | PluvRoomDebug<TIO>;
|
|
134
|
+
limits: PluvClientLimits;
|
|
133
135
|
onAuthorizationFail?: (error: Error) => void;
|
|
134
136
|
metadata?: InputZodLike<TMetadata>;
|
|
135
137
|
publicKey?: PublicKey<TMetadata>;
|
|
@@ -144,6 +146,7 @@ declare class PluvRoom<TIO extends IOLike<any, any>, TMetadata extends JsonObjec
|
|
|
144
146
|
private readonly _debug;
|
|
145
147
|
private readonly _eventNotifier;
|
|
146
148
|
private readonly _intervals;
|
|
149
|
+
private readonly _limits;
|
|
147
150
|
private readonly _listeners;
|
|
148
151
|
private readonly _otherNotifier;
|
|
149
152
|
private readonly _publicKey;
|
|
@@ -235,6 +238,11 @@ declare class PluvRoom<TIO extends IOLike<any, any>, TMetadata extends JsonObjec
|
|
|
235
238
|
type PluvClientOptions<TIO extends IOLike<any, any>, TPresence extends JsonObject, TStorage extends Record<string, CrdtType<any, any>>, TMetadata extends JsonObject> = RoomEndpoints<TIO, TMetadata> & {
|
|
236
239
|
debug?: boolean;
|
|
237
240
|
initialStorage?: AbstractCrdtDocFactory<TStorage>;
|
|
241
|
+
/**
|
|
242
|
+
* @description Configurable limits defined for client-side validation. You should only set
|
|
243
|
+
* this if you control the server and have changed the limits there.
|
|
244
|
+
*/
|
|
245
|
+
limits?: PluvClientLimits;
|
|
238
246
|
metadata?: InputZodLike<TMetadata>;
|
|
239
247
|
presence?: InputZodLike<TPresence>;
|
|
240
248
|
publicKey?: PublicKey<TMetadata>;
|
|
@@ -255,6 +263,7 @@ declare class PluvClient<TIO extends IOLike<any, any>, TPresence extends JsonObj
|
|
|
255
263
|
private readonly _authEndpoint;
|
|
256
264
|
private readonly _debug;
|
|
257
265
|
private readonly _initialStorage?;
|
|
266
|
+
private readonly _limits;
|
|
258
267
|
private readonly _presence?;
|
|
259
268
|
private readonly _publicKey;
|
|
260
269
|
private readonly _rooms;
|
|
@@ -291,6 +300,12 @@ type MergeEventRecords<TEventRecords extends EventRecord<string, any>[], TRoot e
|
|
|
291
300
|
] ? MergeEventRecords<ITail, Omit<TRoot, keyof IHead> & {
|
|
292
301
|
[P in keyof IHead]: TRoot extends Record<P, any> ? TRoot[P] | IHead[P] : IHead[P];
|
|
293
302
|
}> : Id<TRoot>;
|
|
303
|
+
interface PluvClientLimits {
|
|
304
|
+
/**
|
|
305
|
+
* @description Maximum size of presence object in bytes
|
|
306
|
+
*/
|
|
307
|
+
presenceMaxSize?: number | null;
|
|
308
|
+
}
|
|
294
309
|
interface PublicKeyParams<TMetadata extends JsonObject> {
|
|
295
310
|
metadata: TMetadata;
|
|
296
311
|
}
|
|
@@ -368,19 +383,21 @@ type MockedRoomEvents<TIO extends IOLike> = Partial<{
|
|
|
368
383
|
}>;
|
|
369
384
|
type MockedRoomConfig<TIO extends IOLike, TPresence extends JsonObject = {}, TStorage extends Record<string, CrdtType<any, any>> = {}, TEvents extends PluvRouterEventConfig<TIO, TPresence, TStorage> = {}> = {
|
|
370
385
|
events?: MockedRoomEvents<MergeEvents<TEvents, TIO>>;
|
|
386
|
+
limits?: PluvClientLimits;
|
|
371
387
|
router?: PluvRouter<TIO, TPresence, TStorage, TEvents>;
|
|
372
|
-
} & Pick<CrdtManagerOptions<TStorage>, "initialStorage"> & UsersManagerConfig<TPresence>;
|
|
388
|
+
} & Pick<CrdtManagerOptions<TStorage>, "initialStorage"> & Omit<UsersManagerConfig<TPresence>, "limits">;
|
|
373
389
|
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> {
|
|
374
|
-
private _crdtManager;
|
|
375
|
-
private _crdtNotifier;
|
|
376
|
-
private _eventNotifier;
|
|
377
|
-
private _events?;
|
|
378
|
-
private
|
|
379
|
-
private
|
|
390
|
+
private readonly _crdtManager;
|
|
391
|
+
private readonly _crdtNotifier;
|
|
392
|
+
private readonly _eventNotifier;
|
|
393
|
+
private readonly _events?;
|
|
394
|
+
private readonly _limits;
|
|
395
|
+
private readonly _otherNotifier;
|
|
396
|
+
private readonly _router;
|
|
380
397
|
private _state;
|
|
381
|
-
private _stateNotifier;
|
|
382
|
-
private _subscriptions;
|
|
383
|
-
private _usersManager;
|
|
398
|
+
private readonly _stateNotifier;
|
|
399
|
+
private readonly _subscriptions;
|
|
400
|
+
private readonly _usersManager;
|
|
384
401
|
constructor(room: string, options: MockedRoomConfig<TIO, TPresence, TStorage, TEvents>);
|
|
385
402
|
get storageLoaded(): boolean;
|
|
386
403
|
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>; };
|
package/dist/index.js
CHANGED
|
@@ -83,6 +83,9 @@ var AbstractStorageStore = class {
|
|
|
83
83
|
}
|
|
84
84
|
};
|
|
85
85
|
|
|
86
|
+
// src/constants.ts
|
|
87
|
+
var MAX_PRESENCE_SIZE_BYTES = 512;
|
|
88
|
+
|
|
86
89
|
// src/PluvProcedure.ts
|
|
87
90
|
var PluvProcedure = class _PluvProcedure {
|
|
88
91
|
constructor(config = {}) {
|
|
@@ -317,9 +320,6 @@ var StorageStore = class extends AbstractStorageStore {
|
|
|
317
320
|
}
|
|
318
321
|
};
|
|
319
322
|
|
|
320
|
-
// src/constants.ts
|
|
321
|
-
var MAX_PRESENCE_SIZE_BYTES = 512;
|
|
322
|
-
|
|
323
323
|
// src/utils/debounce.ts
|
|
324
324
|
var debounce = (fn, options) => {
|
|
325
325
|
const { wait, immediate = false } = options != null ? options : {};
|
|
@@ -364,8 +364,9 @@ var UsersManager = class {
|
|
|
364
364
|
this._myself = null;
|
|
365
365
|
this._others = /* @__PURE__ */ new Map();
|
|
366
366
|
this._presence = null;
|
|
367
|
-
const { initialPresence, presence = null } = config;
|
|
367
|
+
const { initialPresence, limits, presence = null } = config;
|
|
368
368
|
this.initialPresence = initialPresence;
|
|
369
|
+
this._limits = limits;
|
|
369
370
|
this._myPresence = initialPresence;
|
|
370
371
|
this._presence = presence;
|
|
371
372
|
}
|
|
@@ -498,7 +499,7 @@ var UsersManager = class {
|
|
|
498
499
|
const cleanedPresence = pickBy(this._myPresence, (value) => typeof value !== "undefined");
|
|
499
500
|
const updated = __spreadValues(__spreadValues(__spreadValues({}, this.initialPresence), cleanedPresence), cleanedPatch);
|
|
500
501
|
const bytes = new TextEncoder().encode(JSON.stringify(updated)).length;
|
|
501
|
-
if (bytes >
|
|
502
|
+
if (!!this._limits.presenceMaxSize && bytes > this._limits.presenceMaxSize) {
|
|
502
503
|
throw new Error(
|
|
503
504
|
`Large presence. Presence must be at most 512 bytes. Current size: ${bytes.toLocaleString()}`
|
|
504
505
|
);
|
|
@@ -563,6 +564,7 @@ var PluvRoom = class extends AbstractRoom {
|
|
|
563
564
|
debug = false,
|
|
564
565
|
initialPresence,
|
|
565
566
|
initialStorage,
|
|
567
|
+
limits,
|
|
566
568
|
metadata,
|
|
567
569
|
onAuthorizationFail,
|
|
568
570
|
presence,
|
|
@@ -738,6 +740,7 @@ var PluvRoom = class extends AbstractRoom {
|
|
|
738
740
|
this.metadata = metadata;
|
|
739
741
|
this._debug = debug;
|
|
740
742
|
this._endpoints = { authEndpoint, wsEndpoint };
|
|
743
|
+
this._limits = limits;
|
|
741
744
|
this._reconnectTimeoutMs = reconnectTimeoutMs;
|
|
742
745
|
this._storageStore = storage;
|
|
743
746
|
if (!!publicKey) this._publicKey = publicKey;
|
|
@@ -747,7 +750,7 @@ var PluvRoom = class extends AbstractRoom {
|
|
|
747
750
|
}
|
|
748
751
|
};
|
|
749
752
|
this._router = router != null ? router : new PluvRouter({});
|
|
750
|
-
this._usersManager = new UsersManager({ initialPresence, presence });
|
|
753
|
+
this._usersManager = new UsersManager({ initialPresence, limits: this._limits, presence });
|
|
751
754
|
this._crdtManager = new CrdtManager({ initialStorage });
|
|
752
755
|
}
|
|
753
756
|
get storageLoaded() {
|
|
@@ -1402,6 +1405,7 @@ var PluvClient = class {
|
|
|
1402
1405
|
debug: options.debug,
|
|
1403
1406
|
initialPresence: options.initialPresence,
|
|
1404
1407
|
initialStorage: this._initialStorage,
|
|
1408
|
+
limits: this._limits,
|
|
1405
1409
|
metadata: this.metadata,
|
|
1406
1410
|
onAuthorizationFail: options.onAuthorizationFail,
|
|
1407
1411
|
presence: this._presence,
|
|
@@ -1436,11 +1440,23 @@ var PluvClient = class {
|
|
|
1436
1440
|
this._rooms.delete(toLeave.id);
|
|
1437
1441
|
this._logDebug(`Left and deleted room: ${room}`);
|
|
1438
1442
|
});
|
|
1439
|
-
const {
|
|
1443
|
+
const {
|
|
1444
|
+
authEndpoint,
|
|
1445
|
+
debug = false,
|
|
1446
|
+
initialStorage,
|
|
1447
|
+
limits,
|
|
1448
|
+
metadata,
|
|
1449
|
+
presence,
|
|
1450
|
+
publicKey,
|
|
1451
|
+
wsEndpoint
|
|
1452
|
+
} = options;
|
|
1440
1453
|
this.metadata = metadata;
|
|
1441
1454
|
this._authEndpoint = authEndpoint;
|
|
1442
1455
|
this._debug = debug;
|
|
1443
1456
|
this._initialStorage = initialStorage;
|
|
1457
|
+
this._limits = __spreadValues({
|
|
1458
|
+
presenceMaxSize: MAX_PRESENCE_SIZE_BYTES
|
|
1459
|
+
}, limits);
|
|
1444
1460
|
this._presence = presence;
|
|
1445
1461
|
this._wsEndpoint = wsEndpoint;
|
|
1446
1462
|
if (!!publicKey) this._publicKey = publicKey;
|
|
@@ -1478,7 +1494,7 @@ var infer = (callback) => callback;
|
|
|
1478
1494
|
// src/MockedRoom.ts
|
|
1479
1495
|
var MockedRoom = class extends AbstractRoom {
|
|
1480
1496
|
constructor(room, options) {
|
|
1481
|
-
const { events, initialPresence, initialStorage, presence, router } = options;
|
|
1497
|
+
const { events, initialPresence, initialStorage, limits, presence, router } = options;
|
|
1482
1498
|
super(room);
|
|
1483
1499
|
this._crdtNotifier = new CrdtNotifier();
|
|
1484
1500
|
this._eventNotifier = new EventNotifier();
|
|
@@ -1609,11 +1625,11 @@ var MockedRoom = class extends AbstractRoom {
|
|
|
1609
1625
|
if (!!myself) this._stateNotifier.subjects["myself"].next(myself);
|
|
1610
1626
|
};
|
|
1611
1627
|
this._events = events;
|
|
1628
|
+
this._limits = __spreadValues({
|
|
1629
|
+
presenceMaxSize: MAX_PRESENCE_SIZE_BYTES
|
|
1630
|
+
}, limits);
|
|
1612
1631
|
this._router = router != null ? router : new PluvRouter({});
|
|
1613
|
-
this._usersManager = new UsersManager({
|
|
1614
|
-
initialPresence,
|
|
1615
|
-
presence
|
|
1616
|
-
});
|
|
1632
|
+
this._usersManager = new UsersManager({ initialPresence, limits: this._limits, presence });
|
|
1617
1633
|
this._crdtManager = new CrdtManager({
|
|
1618
1634
|
initialStorage
|
|
1619
1635
|
});
|
package/dist/index.mjs
CHANGED
|
@@ -52,6 +52,9 @@ var AbstractStorageStore = class {
|
|
|
52
52
|
}
|
|
53
53
|
};
|
|
54
54
|
|
|
55
|
+
// src/constants.ts
|
|
56
|
+
var MAX_PRESENCE_SIZE_BYTES = 512;
|
|
57
|
+
|
|
55
58
|
// src/PluvProcedure.ts
|
|
56
59
|
var PluvProcedure = class _PluvProcedure {
|
|
57
60
|
constructor(config = {}) {
|
|
@@ -286,9 +289,6 @@ var StorageStore = class extends AbstractStorageStore {
|
|
|
286
289
|
}
|
|
287
290
|
};
|
|
288
291
|
|
|
289
|
-
// src/constants.ts
|
|
290
|
-
var MAX_PRESENCE_SIZE_BYTES = 512;
|
|
291
|
-
|
|
292
292
|
// src/utils/debounce.ts
|
|
293
293
|
var debounce = (fn, options) => {
|
|
294
294
|
const { wait, immediate = false } = options != null ? options : {};
|
|
@@ -333,8 +333,9 @@ var UsersManager = class {
|
|
|
333
333
|
this._myself = null;
|
|
334
334
|
this._others = /* @__PURE__ */ new Map();
|
|
335
335
|
this._presence = null;
|
|
336
|
-
const { initialPresence, presence = null } = config;
|
|
336
|
+
const { initialPresence, limits, presence = null } = config;
|
|
337
337
|
this.initialPresence = initialPresence;
|
|
338
|
+
this._limits = limits;
|
|
338
339
|
this._myPresence = initialPresence;
|
|
339
340
|
this._presence = presence;
|
|
340
341
|
}
|
|
@@ -467,7 +468,7 @@ var UsersManager = class {
|
|
|
467
468
|
const cleanedPresence = pickBy(this._myPresence, (value) => typeof value !== "undefined");
|
|
468
469
|
const updated = __spreadValues(__spreadValues(__spreadValues({}, this.initialPresence), cleanedPresence), cleanedPatch);
|
|
469
470
|
const bytes = new TextEncoder().encode(JSON.stringify(updated)).length;
|
|
470
|
-
if (bytes >
|
|
471
|
+
if (!!this._limits.presenceMaxSize && bytes > this._limits.presenceMaxSize) {
|
|
471
472
|
throw new Error(
|
|
472
473
|
`Large presence. Presence must be at most 512 bytes. Current size: ${bytes.toLocaleString()}`
|
|
473
474
|
);
|
|
@@ -532,6 +533,7 @@ var PluvRoom = class extends AbstractRoom {
|
|
|
532
533
|
debug = false,
|
|
533
534
|
initialPresence,
|
|
534
535
|
initialStorage,
|
|
536
|
+
limits,
|
|
535
537
|
metadata,
|
|
536
538
|
onAuthorizationFail,
|
|
537
539
|
presence,
|
|
@@ -707,6 +709,7 @@ var PluvRoom = class extends AbstractRoom {
|
|
|
707
709
|
this.metadata = metadata;
|
|
708
710
|
this._debug = debug;
|
|
709
711
|
this._endpoints = { authEndpoint, wsEndpoint };
|
|
712
|
+
this._limits = limits;
|
|
710
713
|
this._reconnectTimeoutMs = reconnectTimeoutMs;
|
|
711
714
|
this._storageStore = storage;
|
|
712
715
|
if (!!publicKey) this._publicKey = publicKey;
|
|
@@ -716,7 +719,7 @@ var PluvRoom = class extends AbstractRoom {
|
|
|
716
719
|
}
|
|
717
720
|
};
|
|
718
721
|
this._router = router != null ? router : new PluvRouter({});
|
|
719
|
-
this._usersManager = new UsersManager({ initialPresence, presence });
|
|
722
|
+
this._usersManager = new UsersManager({ initialPresence, limits: this._limits, presence });
|
|
720
723
|
this._crdtManager = new CrdtManager({ initialStorage });
|
|
721
724
|
}
|
|
722
725
|
get storageLoaded() {
|
|
@@ -1371,6 +1374,7 @@ var PluvClient = class {
|
|
|
1371
1374
|
debug: options.debug,
|
|
1372
1375
|
initialPresence: options.initialPresence,
|
|
1373
1376
|
initialStorage: this._initialStorage,
|
|
1377
|
+
limits: this._limits,
|
|
1374
1378
|
metadata: this.metadata,
|
|
1375
1379
|
onAuthorizationFail: options.onAuthorizationFail,
|
|
1376
1380
|
presence: this._presence,
|
|
@@ -1405,11 +1409,23 @@ var PluvClient = class {
|
|
|
1405
1409
|
this._rooms.delete(toLeave.id);
|
|
1406
1410
|
this._logDebug(`Left and deleted room: ${room}`);
|
|
1407
1411
|
});
|
|
1408
|
-
const {
|
|
1412
|
+
const {
|
|
1413
|
+
authEndpoint,
|
|
1414
|
+
debug = false,
|
|
1415
|
+
initialStorage,
|
|
1416
|
+
limits,
|
|
1417
|
+
metadata,
|
|
1418
|
+
presence,
|
|
1419
|
+
publicKey,
|
|
1420
|
+
wsEndpoint
|
|
1421
|
+
} = options;
|
|
1409
1422
|
this.metadata = metadata;
|
|
1410
1423
|
this._authEndpoint = authEndpoint;
|
|
1411
1424
|
this._debug = debug;
|
|
1412
1425
|
this._initialStorage = initialStorage;
|
|
1426
|
+
this._limits = __spreadValues({
|
|
1427
|
+
presenceMaxSize: MAX_PRESENCE_SIZE_BYTES
|
|
1428
|
+
}, limits);
|
|
1413
1429
|
this._presence = presence;
|
|
1414
1430
|
this._wsEndpoint = wsEndpoint;
|
|
1415
1431
|
if (!!publicKey) this._publicKey = publicKey;
|
|
@@ -1447,7 +1463,7 @@ var infer = (callback) => callback;
|
|
|
1447
1463
|
// src/MockedRoom.ts
|
|
1448
1464
|
var MockedRoom = class extends AbstractRoom {
|
|
1449
1465
|
constructor(room, options) {
|
|
1450
|
-
const { events, initialPresence, initialStorage, presence, router } = options;
|
|
1466
|
+
const { events, initialPresence, initialStorage, limits, presence, router } = options;
|
|
1451
1467
|
super(room);
|
|
1452
1468
|
this._crdtNotifier = new CrdtNotifier();
|
|
1453
1469
|
this._eventNotifier = new EventNotifier();
|
|
@@ -1578,11 +1594,11 @@ var MockedRoom = class extends AbstractRoom {
|
|
|
1578
1594
|
if (!!myself) this._stateNotifier.subjects["myself"].next(myself);
|
|
1579
1595
|
};
|
|
1580
1596
|
this._events = events;
|
|
1597
|
+
this._limits = __spreadValues({
|
|
1598
|
+
presenceMaxSize: MAX_PRESENCE_SIZE_BYTES
|
|
1599
|
+
}, limits);
|
|
1581
1600
|
this._router = router != null ? router : new PluvRouter({});
|
|
1582
|
-
this._usersManager = new UsersManager({
|
|
1583
|
-
initialPresence,
|
|
1584
|
-
presence
|
|
1585
|
-
});
|
|
1601
|
+
this._usersManager = new UsersManager({ initialPresence, limits: this._limits, presence });
|
|
1586
1602
|
this._crdtManager = new CrdtManager({
|
|
1587
1603
|
initialStorage
|
|
1588
1604
|
});
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@pluv/client",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.43.0",
|
|
4
4
|
"description": "@pluv/io frontend client",
|
|
5
5
|
"author": "leedavidcs",
|
|
6
6
|
"license": "MIT",
|
|
@@ -18,15 +18,15 @@
|
|
|
18
18
|
},
|
|
19
19
|
"dependencies": {
|
|
20
20
|
"wonka": "^6.3.5",
|
|
21
|
-
"@pluv/crdt": "^0.
|
|
22
|
-
"@pluv/types": "^0.
|
|
21
|
+
"@pluv/crdt": "^0.43.0",
|
|
22
|
+
"@pluv/types": "^0.43.0"
|
|
23
23
|
},
|
|
24
24
|
"devDependencies": {
|
|
25
25
|
"eslint": "^9.25.1",
|
|
26
26
|
"tsup": "^8.4.0",
|
|
27
27
|
"typescript": "^5.8.3",
|
|
28
|
-
"@pluv/tsconfig": "^0.
|
|
29
|
-
"eslint-config-pluv": "^0.
|
|
28
|
+
"@pluv/tsconfig": "^0.43.0",
|
|
29
|
+
"eslint-config-pluv": "^0.43.0"
|
|
30
30
|
},
|
|
31
31
|
"scripts": {
|
|
32
32
|
"build": "tsup src/index.ts --format esm,cjs --dts",
|
package/src/MockedRoom.ts
CHANGED
|
@@ -20,11 +20,13 @@ import type {
|
|
|
20
20
|
EventResolver,
|
|
21
21
|
EventResolverContext,
|
|
22
22
|
InternalSubscriptions,
|
|
23
|
+
PluvClientLimits,
|
|
23
24
|
UpdateMyPresenceAction,
|
|
24
25
|
UserInfo,
|
|
25
26
|
WebSocketConnection,
|
|
26
27
|
WebSocketState,
|
|
27
28
|
} from "./types";
|
|
29
|
+
import { MAX_PRESENCE_SIZE_BYTES } from "./constants";
|
|
28
30
|
|
|
29
31
|
export type MockedRoomEvents<TIO extends IOLike> = Partial<{
|
|
30
32
|
[P in keyof InferIOInput<TIO>]: (data: Id<InferIOInput<TIO>[P]>) => Partial<InferIOOutput<TIO>>;
|
|
@@ -37,9 +39,10 @@ export type MockedRoomConfig<
|
|
|
37
39
|
TEvents extends PluvRouterEventConfig<TIO, TPresence, TStorage> = {},
|
|
38
40
|
> = {
|
|
39
41
|
events?: MockedRoomEvents<MergeEvents<TEvents, TIO>>;
|
|
42
|
+
limits?: PluvClientLimits;
|
|
40
43
|
router?: PluvRouter<TIO, TPresence, TStorage, TEvents>;
|
|
41
44
|
} & Pick<CrdtManagerOptions<TStorage>, "initialStorage"> &
|
|
42
|
-
UsersManagerConfig<TPresence>;
|
|
45
|
+
Omit<UsersManagerConfig<TPresence>, "limits">;
|
|
43
46
|
|
|
44
47
|
export class MockedRoom<
|
|
45
48
|
TIO extends IOLike,
|
|
@@ -47,12 +50,13 @@ export class MockedRoom<
|
|
|
47
50
|
TStorage extends Record<string, CrdtType<any, any>> = {},
|
|
48
51
|
TEvents extends PluvRouterEventConfig<TIO, TPresence, TStorage> = {},
|
|
49
52
|
> extends AbstractRoom<TIO, TPresence, TStorage> {
|
|
50
|
-
private _crdtManager: CrdtManager<TStorage>;
|
|
51
|
-
private _crdtNotifier = new CrdtNotifier<TStorage>();
|
|
52
|
-
private _eventNotifier = new EventNotifier<MergeEvents<TEvents, TIO>>();
|
|
53
|
-
private _events?: MockedRoomEvents<MergeEvents<TEvents, TIO>>;
|
|
54
|
-
private
|
|
55
|
-
private
|
|
53
|
+
private readonly _crdtManager: CrdtManager<TStorage>;
|
|
54
|
+
private readonly _crdtNotifier = new CrdtNotifier<TStorage>();
|
|
55
|
+
private readonly _eventNotifier = new EventNotifier<MergeEvents<TEvents, TIO>>();
|
|
56
|
+
private readonly _events?: MockedRoomEvents<MergeEvents<TEvents, TIO>>;
|
|
57
|
+
private readonly _limits: PluvClientLimits;
|
|
58
|
+
private readonly _otherNotifier = new OtherNotifier<TIO, TPresence>();
|
|
59
|
+
private readonly _router: PluvRouter<TIO, TPresence, TStorage, TEvents>;
|
|
56
60
|
private _state: WebSocketState<TIO> = {
|
|
57
61
|
authorization: {
|
|
58
62
|
token: null,
|
|
@@ -66,24 +70,24 @@ export class MockedRoom<
|
|
|
66
70
|
},
|
|
67
71
|
webSocket: null,
|
|
68
72
|
};
|
|
69
|
-
private _stateNotifier = new StateNotifier<TIO, TPresence>();
|
|
70
|
-
private _subscriptions: InternalSubscriptions = {
|
|
73
|
+
private readonly _stateNotifier = new StateNotifier<TIO, TPresence>();
|
|
74
|
+
private readonly _subscriptions: InternalSubscriptions = {
|
|
71
75
|
observeCrdt: null,
|
|
72
76
|
};
|
|
73
|
-
private _usersManager: UsersManager<TIO, TPresence>;
|
|
77
|
+
private readonly _usersManager: UsersManager<TIO, TPresence>;
|
|
74
78
|
|
|
75
79
|
constructor(room: string, options: MockedRoomConfig<TIO, TPresence, TStorage, TEvents>) {
|
|
76
|
-
const { events, initialPresence, initialStorage, presence, router } = options;
|
|
80
|
+
const { events, initialPresence, initialStorage, limits, presence, router } = options;
|
|
77
81
|
|
|
78
82
|
super(room);
|
|
79
83
|
|
|
80
84
|
this._events = events;
|
|
81
|
-
|
|
85
|
+
this._limits = {
|
|
86
|
+
presenceMaxSize: MAX_PRESENCE_SIZE_BYTES,
|
|
87
|
+
...limits,
|
|
88
|
+
};
|
|
82
89
|
this._router = router ?? (new PluvRouter({}) as PluvRouter<TIO, TPresence, TStorage, TEvents>);
|
|
83
|
-
this._usersManager = new UsersManager<TIO, TPresence>({
|
|
84
|
-
initialPresence,
|
|
85
|
-
presence,
|
|
86
|
-
});
|
|
90
|
+
this._usersManager = new UsersManager<TIO, TPresence>({ initialPresence, limits: this._limits, presence });
|
|
87
91
|
|
|
88
92
|
this._crdtManager = new CrdtManager<TStorage>({
|
|
89
93
|
initialStorage,
|
package/src/PluvClient.ts
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import type { AbstractCrdtDocFactory, CrdtType } from "@pluv/crdt";
|
|
2
2
|
import type { InputZodLike, IOLike, JsonObject } from "@pluv/types";
|
|
3
|
+
import { MAX_PRESENCE_SIZE_BYTES } from "./constants";
|
|
3
4
|
import type { InferCallback } from "./infer";
|
|
4
5
|
import { PluvProcedure } from "./PluvProcedure";
|
|
5
6
|
import type {
|
|
@@ -14,7 +15,7 @@ import type {
|
|
|
14
15
|
import { PluvRoom } from "./PluvRoom";
|
|
15
16
|
import type { PluvRouterEventConfig } from "./PluvRouter";
|
|
16
17
|
import { PluvRouter } from "./PluvRouter";
|
|
17
|
-
import type { PublicKey, WithMetadata } from "./types";
|
|
18
|
+
import type { PluvClientLimits, PublicKey, WithMetadata } from "./types";
|
|
18
19
|
|
|
19
20
|
export type PluvClientOptions<
|
|
20
21
|
TIO extends IOLike<any, any>,
|
|
@@ -24,6 +25,11 @@ export type PluvClientOptions<
|
|
|
24
25
|
> = RoomEndpoints<TIO, TMetadata> & {
|
|
25
26
|
debug?: boolean;
|
|
26
27
|
initialStorage?: AbstractCrdtDocFactory<TStorage>;
|
|
28
|
+
/**
|
|
29
|
+
* @description Configurable limits defined for client-side validation. You should only set
|
|
30
|
+
* this if you control the server and have changed the limits there.
|
|
31
|
+
*/
|
|
32
|
+
limits?: PluvClientLimits;
|
|
27
33
|
metadata?: InputZodLike<TMetadata>;
|
|
28
34
|
presence?: InputZodLike<TPresence>;
|
|
29
35
|
publicKey?: PublicKey<TMetadata>;
|
|
@@ -61,6 +67,7 @@ export class PluvClient<
|
|
|
61
67
|
private readonly _authEndpoint: AuthEndpoint<TMetadata> | undefined;
|
|
62
68
|
private readonly _debug: boolean;
|
|
63
69
|
private readonly _initialStorage?: AbstractCrdtDocFactory<TStorage>;
|
|
70
|
+
private readonly _limits: PluvClientLimits;
|
|
64
71
|
private readonly _presence?: InputZodLike<TPresence>;
|
|
65
72
|
private readonly _publicKey: PublicKey<TMetadata> | null = null;
|
|
66
73
|
private readonly _rooms = new Map<string, PluvRoom<TIO, TMetadata, TPresence, TStorage, any>>();
|
|
@@ -77,13 +84,26 @@ export class PluvClient<
|
|
|
77
84
|
}
|
|
78
85
|
|
|
79
86
|
constructor(options: PluvClientOptions<TIO, TPresence, TStorage, TMetadata>) {
|
|
80
|
-
const {
|
|
87
|
+
const {
|
|
88
|
+
authEndpoint,
|
|
89
|
+
debug = false,
|
|
90
|
+
initialStorage,
|
|
91
|
+
limits,
|
|
92
|
+
metadata,
|
|
93
|
+
presence,
|
|
94
|
+
publicKey,
|
|
95
|
+
wsEndpoint,
|
|
96
|
+
} = options;
|
|
81
97
|
|
|
82
98
|
this.metadata = metadata;
|
|
83
99
|
|
|
84
100
|
this._authEndpoint = authEndpoint as AuthEndpoint<TMetadata>;
|
|
85
101
|
this._debug = debug;
|
|
86
102
|
this._initialStorage = initialStorage;
|
|
103
|
+
this._limits = {
|
|
104
|
+
presenceMaxSize: MAX_PRESENCE_SIZE_BYTES,
|
|
105
|
+
...limits,
|
|
106
|
+
};
|
|
87
107
|
this._presence = presence;
|
|
88
108
|
this._wsEndpoint = wsEndpoint;
|
|
89
109
|
|
|
@@ -104,6 +124,7 @@ export class PluvClient<
|
|
|
104
124
|
debug: options.debug,
|
|
105
125
|
initialPresence: options.initialPresence,
|
|
106
126
|
initialStorage: this._initialStorage,
|
|
127
|
+
limits: this._limits,
|
|
107
128
|
metadata: this.metadata,
|
|
108
129
|
onAuthorizationFail: options.onAuthorizationFail,
|
|
109
130
|
presence: this._presence,
|
package/src/PluvRoom.ts
CHANGED
|
@@ -37,6 +37,7 @@ import type {
|
|
|
37
37
|
EventResolver,
|
|
38
38
|
EventResolverContext,
|
|
39
39
|
InternalSubscriptions,
|
|
40
|
+
PluvClientLimits,
|
|
40
41
|
PublicKey,
|
|
41
42
|
UpdateMyPresenceAction,
|
|
42
43
|
UserInfo,
|
|
@@ -169,6 +170,7 @@ export type RoomConfig<
|
|
|
169
170
|
{
|
|
170
171
|
addons?: readonly PluvRoomAddon<TIO, TMetadata, TPresence, TStorage>[];
|
|
171
172
|
debug?: boolean | PluvRoomDebug<TIO>;
|
|
173
|
+
limits: PluvClientLimits;
|
|
172
174
|
onAuthorizationFail?: (error: Error) => void;
|
|
173
175
|
metadata?: InputZodLike<TMetadata>;
|
|
174
176
|
publicKey?: PublicKey<TMetadata>;
|
|
@@ -197,6 +199,7 @@ export class PluvRoom<
|
|
|
197
199
|
private readonly _intervals: IntervalIds = {
|
|
198
200
|
heartbeat: null,
|
|
199
201
|
};
|
|
202
|
+
private readonly _limits: PluvClientLimits;
|
|
200
203
|
private readonly _listeners: InternalListeners;
|
|
201
204
|
private readonly _otherNotifier = new OtherNotifier<TIO, TPresence>();
|
|
202
205
|
private readonly _publicKey: PublicKey<TMetadata> | null = null;
|
|
@@ -237,6 +240,7 @@ export class PluvRoom<
|
|
|
237
240
|
debug = false,
|
|
238
241
|
initialPresence,
|
|
239
242
|
initialStorage,
|
|
243
|
+
limits,
|
|
240
244
|
metadata,
|
|
241
245
|
onAuthorizationFail,
|
|
242
246
|
presence,
|
|
@@ -259,6 +263,7 @@ export class PluvRoom<
|
|
|
259
263
|
|
|
260
264
|
this._debug = debug;
|
|
261
265
|
this._endpoints = { authEndpoint, wsEndpoint } as RoomEndpoints<TIO, TMetadata>;
|
|
266
|
+
this._limits = limits;
|
|
262
267
|
this._reconnectTimeoutMs = reconnectTimeoutMs;
|
|
263
268
|
this._storageStore = storage;
|
|
264
269
|
|
|
@@ -271,7 +276,7 @@ export class PluvRoom<
|
|
|
271
276
|
};
|
|
272
277
|
|
|
273
278
|
this._router = router ?? (new PluvRouter({}) as PluvRouter<TIO, TPresence, TStorage, TEvents>);
|
|
274
|
-
this._usersManager = new UsersManager<TIO, TPresence>({ initialPresence, presence });
|
|
279
|
+
this._usersManager = new UsersManager<TIO, TPresence>({ initialPresence, limits: this._limits, presence });
|
|
275
280
|
this._crdtManager = new CrdtManager<TStorage>({ initialStorage });
|
|
276
281
|
}
|
|
277
282
|
|
package/src/UsersManager.ts
CHANGED
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
import type { InputZodLike, IOLike, JsonObject, OptionalProps } from "@pluv/types";
|
|
2
|
-
import {
|
|
3
|
-
import type { UserInfo } from "./types";
|
|
2
|
+
import type { PluvClientLimits, UserInfo } from "./types";
|
|
4
3
|
import { pickBy } from "./utils";
|
|
5
4
|
|
|
6
5
|
export type Presence = Record<string, unknown>;
|
|
7
6
|
|
|
8
7
|
export type UsersManagerConfig<TPresence extends JsonObject = {}> = {
|
|
9
8
|
initialPresence?: TPresence;
|
|
9
|
+
limits: PluvClientLimits;
|
|
10
10
|
presence?: InputZodLike<TPresence>;
|
|
11
11
|
};
|
|
12
12
|
|
|
@@ -24,12 +24,13 @@ export type DeleteConnectionResult<TIO extends IOLike, TPresence extends JsonObj
|
|
|
24
24
|
};
|
|
25
25
|
|
|
26
26
|
export class UsersManager<TIO extends IOLike, TPresence extends JsonObject = {}> {
|
|
27
|
-
|
|
27
|
+
public readonly initialPresence: TPresence;
|
|
28
|
+
|
|
29
|
+
private readonly _idMap = {
|
|
28
30
|
fromConnectionId: new Map<[connectionId: string][0], [clientId: string][0]>(),
|
|
29
31
|
fromClientId: new Map<[clientId: string][0], Set<[connectionId: string][0]>>(),
|
|
30
32
|
};
|
|
31
|
-
|
|
32
|
-
public readonly initialPresence: TPresence;
|
|
33
|
+
private _limits: PluvClientLimits;
|
|
33
34
|
/**
|
|
34
35
|
* @description This presence can be updated while the user is not
|
|
35
36
|
* connected.
|
|
@@ -43,10 +44,11 @@ export class UsersManager<TIO extends IOLike, TPresence extends JsonObject = {}>
|
|
|
43
44
|
private _presence: InputZodLike<TPresence> | null = null;
|
|
44
45
|
|
|
45
46
|
constructor(config: UsersManagerConfig<TPresence>) {
|
|
46
|
-
const { initialPresence, presence = null } = config;
|
|
47
|
+
const { initialPresence, limits, presence = null } = config;
|
|
47
48
|
|
|
48
49
|
this.initialPresence = initialPresence as TPresence;
|
|
49
50
|
|
|
51
|
+
this._limits = limits;
|
|
50
52
|
this._myPresence = initialPresence as TPresence;
|
|
51
53
|
this._presence = presence;
|
|
52
54
|
}
|
|
@@ -256,7 +258,7 @@ export class UsersManager<TIO extends IOLike, TPresence extends JsonObject = {}>
|
|
|
256
258
|
const updated = { ...this.initialPresence, ...cleanedPresence, ...cleanedPatch } as TPresence;
|
|
257
259
|
const bytes = new TextEncoder().encode(JSON.stringify(updated)).length;
|
|
258
260
|
|
|
259
|
-
if (bytes >
|
|
261
|
+
if (!!this._limits.presenceMaxSize && bytes > this._limits.presenceMaxSize) {
|
|
260
262
|
throw new Error(
|
|
261
263
|
`Large presence. Presence must be at most 512 bytes. Current size: ${bytes.toLocaleString()}`,
|
|
262
264
|
);
|
package/src/types.ts
CHANGED
|
@@ -57,6 +57,13 @@ export type MergeEventRecords<
|
|
|
57
57
|
>
|
|
58
58
|
: Id<TRoot>;
|
|
59
59
|
|
|
60
|
+
export interface PluvClientLimits {
|
|
61
|
+
/**
|
|
62
|
+
* @description Maximum size of presence object in bytes
|
|
63
|
+
*/
|
|
64
|
+
presenceMaxSize?: number | null;
|
|
65
|
+
}
|
|
66
|
+
|
|
60
67
|
export interface PublicKeyParams<TMetadata extends JsonObject> {
|
|
61
68
|
metadata: TMetadata;
|
|
62
69
|
}
|