@pluv/io 5.0.1 → 5.0.2

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/src/PluvServer.ts DELETED
@@ -1,487 +0,0 @@
1
- import type { AbstractCrdtDocFactory, CrdtLibraryType, NoopCrdtDocFactory } from "@pluv/crdt";
2
- import { noop } from "@pluv/crdt";
3
- import type {
4
- AreAllOptional,
5
- IOLike,
6
- Id,
7
- InferIOAuthorize,
8
- InferIOAuthorizeUser,
9
- JsonObject,
10
- Maybe,
11
- NonNilProps,
12
- } from "@pluv/types";
13
- import colors from "kleur";
14
- import type {
15
- AbstractPlatform,
16
- InferInitContextType,
17
- InferRoomContextType,
18
- } from "./AbstractPlatform";
19
- import { IORoom } from "./IORoom";
20
- import type { PluvIO } from "./PluvIO";
21
- import { PluvProcedure } from "./PluvProcedure";
22
- import type { PluvRouterEventConfig } from "./PluvRouter";
23
- import { PluvRouter } from "./PluvRouter";
24
- import type { JWTEncodeParams } from "./authorize";
25
- import { PING_TIMEOUT_MS } from "./constants";
26
- import type {
27
- BasePluvIOListeners,
28
- GetInitialStorageFn,
29
- PluvContext,
30
- PluvIOAuthorize,
31
- PluvIOLimits,
32
- PluvIOListeners,
33
- } from "./types";
34
- import { oneLine, pickBy } from "./utils";
35
- import { __PLUV_VERSION } from "./version";
36
-
37
- export type InferIORoom<TServer extends PluvServer<any, any, any, any, any>> =
38
- TServer extends PluvServer<
39
- infer IPlatform,
40
- infer IAuthorize,
41
- infer IContext,
42
- infer ICrdt,
43
- infer IEvents
44
- >
45
- ? IORoom<IPlatform, IAuthorize, IContext, ICrdt, IEvents>
46
- : never;
47
-
48
- export type PluvServerConfig<
49
- TPlatform extends AbstractPlatform<any, any> = AbstractPlatform<any, any>,
50
- TAuthorize extends PluvIOAuthorize<TPlatform, any, InferInitContextType<TPlatform>> | null =
51
- any,
52
- TContext extends Record<string, any> = {},
53
- TCrdt extends CrdtLibraryType<any> = CrdtLibraryType<any>,
54
- TEvents extends PluvRouterEventConfig<TPlatform, TAuthorize, TContext> = {},
55
- > = Partial<PluvIOListeners<TPlatform, TAuthorize, TContext, TEvents>> & {
56
- authorize?: TAuthorize;
57
- context?: PluvContext<TPlatform, TContext>;
58
- crdt?: { doc: (value: any) => AbstractCrdtDocFactory<any, any> };
59
- debug?: boolean;
60
- limits: PluvIOLimits;
61
- io: PluvIO<TPlatform, TAuthorize, TContext>;
62
- platform: () => TPlatform;
63
- router?: PluvRouter<TPlatform, TAuthorize, TContext, TEvents>;
64
- } & (TCrdt extends CrdtLibraryType<NoopCrdtDocFactory>
65
- ? { getInitialStorage?: "[ERROR]: Must specify crdt to use getInitialStorage" }
66
- : { getInitialStorage: GetInitialStorageFn<TContext> });
67
-
68
- type BaseCreateRoomOptions<
69
- TPlatform extends AbstractPlatform<any, any>,
70
- TAuthorize extends PluvIOAuthorize<TPlatform, any, InferInitContextType<TPlatform>> | null,
71
- TContext extends Record<string, any>,
72
- TEvents extends PluvRouterEventConfig<TPlatform, TAuthorize, TContext>,
73
- > = {
74
- debug?: boolean;
75
- };
76
-
77
- export type CreateRoomOptions<
78
- TPlatform extends AbstractPlatform<any, any>,
79
- TAuthorize extends PluvIOAuthorize<TPlatform, any, InferInitContextType<TPlatform>> | null,
80
- TContext extends Record<string, any>,
81
- TEvents extends PluvRouterEventConfig<TPlatform, TAuthorize, TContext>,
82
- > = keyof Omit<InferRoomContextType<TPlatform>, "meta"> extends never
83
- ? [BaseCreateRoomOptions<TPlatform, TAuthorize, TContext, TEvents>] | []
84
- : [
85
- Id<
86
- BaseCreateRoomOptions<TPlatform, TAuthorize, TContext, TEvents> &
87
- InferRoomContextType<TPlatform>
88
- >,
89
- ];
90
-
91
- export class PluvServer<
92
- TPlatform extends AbstractPlatform<any, any> = AbstractPlatform<any, any>,
93
- TAuthorize extends PluvIOAuthorize<TPlatform, any, InferInitContextType<TPlatform>> | null =
94
- any,
95
- TContext extends Record<string, any> = {},
96
- TCrdt extends CrdtLibraryType<any> = CrdtLibraryType<any>,
97
- TEvents extends PluvRouterEventConfig<TPlatform, TAuthorize, TContext> = {},
98
- > implements IOLike<TAuthorize, TCrdt, TEvents> {
99
- public readonly version: string = __PLUV_VERSION as any;
100
-
101
- private readonly _config: NonNilProps<
102
- PluvServerConfig<TPlatform, TAuthorize, TContext, TCrdt, TEvents>
103
- >;
104
- private readonly _docFactory: AbstractCrdtDocFactory<any, any>;
105
-
106
- public get fetch(): (...args: any[]) => Promise<any> {
107
- return (...args: any[]): Promise<any> => {
108
- const platform = this._config.platform();
109
- platform.validateConfig(this._config);
110
-
111
- if (!platform._fetch) {
112
- throw new Error(`\`${platform._name}\` does not support \`fetch\``);
113
- }
114
-
115
- return platform._fetch(...args);
116
- };
117
- }
118
-
119
- /**
120
- * @ignore
121
- * @readonly
122
- * @deprecated Internal use only. Changes to this will never be marked as breaking.
123
- */
124
- public get _defs() {
125
- return {
126
- authorize: this._config.authorize,
127
- context: this._config.context,
128
- crdt: this._config.crdt,
129
- events: this._router._defs.events,
130
- platform: this._config.platform(),
131
- } as {
132
- authorize: TAuthorize;
133
- context: PluvContext<TPlatform, TContext>;
134
- crdt: TCrdt;
135
- events: TEvents;
136
- platform: TPlatform;
137
- };
138
- }
139
-
140
- private get _baseRouter(): PluvRouter<TPlatform, TAuthorize, TContext, {}> {
141
- const listeners = this._getListeners();
142
-
143
- return new PluvRouter({
144
- $getOthers: this._procedure.sync((data, { room, session, sessions }) => {
145
- const currentTime = Date.now();
146
-
147
- const others = sessions
148
- .filter((wsSession) => {
149
- if (wsSession.id === session?.id) return false;
150
- if (wsSession.quit) return false;
151
- if (currentTime - wsSession.timers.ping > PING_TIMEOUT_MS) return false;
152
-
153
- return true;
154
- })
155
- .reduce<{
156
- [connectionId: string]: {
157
- connectionId: string;
158
- room: string | null;
159
- user: JsonObject | null;
160
- };
161
- }>(
162
- (acc, { id, presence, timers, user }) => ({
163
- ...acc,
164
- [id]: {
165
- connectionId: id,
166
- presence,
167
- room,
168
- timers: { presence: timers.presence },
169
- user,
170
- },
171
- }),
172
- {},
173
- );
174
-
175
- return { $othersReceived: { others } };
176
- }),
177
- $initializeSession: this._procedure
178
- .broadcast((data, { session }) => {
179
- const presence = (data as any)?.presence;
180
- const timers = session.timers;
181
-
182
- if (!session) return {};
183
-
184
- session.presence = presence;
185
-
186
- return {
187
- $userJoined: {
188
- connectionId: session.id,
189
- user: session.user,
190
- presence,
191
- timers: { presence: timers.presence },
192
- },
193
- };
194
- })
195
- .self(async (data, { context, doc, platform, room, session }) => {
196
- const oldState = await platform.persistence.getStorageState(room);
197
- /**
198
- * !HACK
199
- * @description This is the frontend's initialStorage. We only want to
200
- * apply this if the server's storage is empty (i.e. no initial storage
201
- * has been applied)
202
- */
203
- const update = (data as any)?.update as Maybe<string>;
204
-
205
- if (!oldState) {
206
- const loadedState = await this._getInitialStorage({ context, room });
207
-
208
- if (!!loadedState && !this._docFactory.isEmpty(loadedState)) {
209
- doc.applyEncodedState({ update: loadedState });
210
- }
211
- }
212
-
213
- /**
214
- * @description Storage was already initialized. Don't overwrite the current
215
- * storage state with the incoming initial storage. Return what the current state
216
- * is without changes.
217
- * @date May 7, 2025
218
- */
219
- if (!doc.isEmpty()) {
220
- const encodedState = doc.getEncodedState();
221
-
222
- return {
223
- $storageReceived: { changeKind: "unchanged", state: encodedState },
224
- };
225
- }
226
-
227
- /**
228
- * @description Storage was never initialized, and there is an incoming
229
- * initialStorage from the client. Apply the initialStorage and persist the state
230
- * as an update.
231
- * @date May 7, 2025
232
- */
233
- if (!!update) {
234
- const encodedState = doc.applyEncodedState({ update }).getEncodedState();
235
- const storageSize = new TextEncoder().encode(encodedState).length;
236
-
237
- if (
238
- !!this._config.limits.storageMaxSize &&
239
- storageSize > this._config.limits.storageMaxSize
240
- ) {
241
- throw new Error("Storage has exceeded the size limit");
242
- }
243
-
244
- await platform.persistence
245
- .setStorageState(room, encodedState)
246
- .catch((error) => {
247
- this._logDebug(error);
248
- });
249
-
250
- listeners.onStorageUpdated({
251
- context,
252
- encodedState,
253
- platform,
254
- room,
255
- user: session?.user,
256
- webSocket: session?.webSocket.webSocket,
257
- });
258
-
259
- return {
260
- $storageReceived: { changeKind: "initialized", state: encodedState },
261
- };
262
- }
263
-
264
- const encodedState = doc.getEncodedState();
265
-
266
- return { $storageReceived: { changeKind: "empty", state: encodedState } };
267
- }),
268
- $ping: this._procedure.self((data, { platform, session }) => {
269
- if (!session) return {};
270
-
271
- const currentTime = new Date().getTime();
272
- const prevState = session.webSocket.state;
273
-
274
- platform.setSerializedState(session.webSocket, {
275
- ...prevState,
276
- timers: {
277
- ...prevState.timers,
278
- ping: currentTime,
279
- },
280
- });
281
-
282
- return { $pong: {} };
283
- }),
284
- $updatePresence: this._procedure.broadcast((data, context) => {
285
- const presence = (data as any)?.presence;
286
- const { session } = context;
287
-
288
- if (!session) return {};
289
-
290
- const cleanedPatch = pickBy(
291
- presence ?? {},
292
- (value) => typeof value !== "undefined",
293
- );
294
- const updated = Object.assign(Object.create(null), session.presence, cleanedPatch);
295
- const bytes = new TextEncoder().encode(JSON.stringify(updated)).length;
296
-
297
- if (
298
- !!this._config.limits.presenceMaxSize &&
299
- bytes > this._config.limits.presenceMaxSize
300
- ) {
301
- throw new Error(oneLine`
302
- Large presence. Presence must be at most
303
- ${this._config.limits.presenceMaxSize.toLocaleString()} bytes.
304
- Current size: ${bytes.toLocaleString()} bytes
305
- `);
306
- }
307
-
308
- context.presence = updated;
309
-
310
- return {
311
- $presenceUpdated: {
312
- presence: updated,
313
- timers: { presence: session.timers.presence },
314
- },
315
- };
316
- }),
317
- $updateStorage: this._procedure.broadcast((data, { context, doc, platform, room }) => {
318
- const origin = (data as any)?.origin as Maybe<string>;
319
- const update: string | null = (data as any)?.update ?? null;
320
-
321
- if (origin === "$initialized" && Object.keys(doc.toJson()).length) return {};
322
-
323
- const updated = update === null ? doc : doc.applyEncodedState({ update });
324
- const encodedState = updated.getEncodedState();
325
- const storageSize = new TextEncoder().encode(encodedState).length;
326
-
327
- if (
328
- !!this._config.limits.storageMaxSize &&
329
- storageSize > this._config.limits.storageMaxSize
330
- ) {
331
- throw new Error(oneLine`
332
- Large Storage. Storage must be at most
333
- ${this._config.limits.storageMaxSize.toLocaleString()} bytes.
334
- Current size: ${storageSize.toLocaleString()} bytes
335
- `);
336
- }
337
-
338
- platform.persistence.setStorageState(room, encodedState).then(() => {
339
- listeners.onStorageUpdated({
340
- context,
341
- encodedState,
342
- platform,
343
- room,
344
- });
345
- });
346
-
347
- return { $storageUpdated: { state: encodedState } };
348
- }),
349
- });
350
- }
351
-
352
- private get _procedure(): PluvProcedure<TPlatform, TAuthorize, TContext, {}, {}> {
353
- return new PluvProcedure();
354
- }
355
-
356
- private get _router(): PluvRouter<TPlatform, TAuthorize, TContext, TEvents> {
357
- return (
358
- this._config.router
359
- ? PluvRouter.merge(this._baseRouter, this._config.router)
360
- : this._baseRouter
361
- ) as PluvRouter<TPlatform, TAuthorize, TContext, TEvents>;
362
- }
363
-
364
- constructor(options: PluvServerConfig<TPlatform, TAuthorize, TContext, TCrdt, TEvents>) {
365
- this._config = {
366
- crdt: noop,
367
- debug: false,
368
- router: new PluvRouter<TPlatform, TAuthorize, TContext, TEvents>({} as TEvents),
369
- ...options,
370
- } as NonNilProps<PluvServerConfig<TPlatform, TAuthorize, TContext, TCrdt, TEvents>>;
371
-
372
- const {
373
- onRoomDestroyed,
374
- onRoomMessage,
375
- onStorageDestroyed,
376
- onStorageUpdated,
377
- onUserConnected,
378
- onUserDisconnected,
379
- } = options as Partial<BasePluvIOListeners<TPlatform, TAuthorize, TContext, TEvents>>;
380
-
381
- this._docFactory = this._config.crdt.doc(() => ({}));
382
- (this as any)._listeners = {
383
- onRoomDestroyed: (event) => onRoomDestroyed?.(event),
384
- onRoomMessage: (event) => onRoomMessage?.(event),
385
- onStorageDestroyed: (event) => onStorageDestroyed?.(event),
386
- onStorageUpdated: (event) => onStorageUpdated?.(event),
387
- onUserConnected: (event) => onUserConnected?.(event),
388
- onUserDisconnected: (event) => onUserDisconnected?.(event),
389
- } as BasePluvIOListeners<TPlatform, TAuthorize, TContext, TEvents>;
390
- }
391
-
392
- public createRoom(
393
- room: string,
394
- ...options: CreateRoomOptions<TPlatform, TAuthorize, TContext, TEvents>
395
- ): IORoom<TPlatform, TAuthorize, TContext, TCrdt, TEvents> {
396
- const { _meta, debug, ...platformRoomContext } = (options[0] ?? {}) as CreateRoomOptions<
397
- TPlatform,
398
- TAuthorize,
399
- TContext,
400
- TEvents
401
- >[0] & {
402
- _meta?: any;
403
- };
404
-
405
- const platform = this._config.platform();
406
-
407
- platform.validateConfig(this._config);
408
-
409
- if (platform._config.handleMode !== "io") {
410
- throw new Error(`\`createRoom\` is unsupported for \`${platform._name}\``);
411
- }
412
-
413
- if (!/^[a-z0-9](?:[a-z0-9-_]*[a-z0-9])?$/i.test(room))
414
- throw new Error("Unsupported room name");
415
-
416
- const roomContext = platformRoomContext as InferRoomContextType<TPlatform>;
417
- const listeners = this._getListeners();
418
- const logDebug = this._logDebug.bind(this);
419
-
420
- const newRoom = new IORoom<TPlatform, TAuthorize, TContext, TCrdt, TEvents>(room, {
421
- ...(!!_meta ? { _meta } : {}),
422
- authorize: this._config.authorize ?? undefined,
423
- context: this._config.context,
424
- crdt: this._config.crdt,
425
- debug: debug ?? this._config.debug,
426
- getInitialStorage: this._getInitialStorage,
427
- async onRoomDestroyed(event) {
428
- logDebug(`${colors.blue("Deleting empty room:")} ${room}`);
429
-
430
- // Always fire server-level onRoomDestroyed
431
- await Promise.resolve(listeners.onRoomDestroyed(event));
432
-
433
- logDebug(`${colors.blue("Deleted room:")} ${room}`);
434
- },
435
- async onStorageDestroyed(event) {
436
- logDebug(`${colors.blue("Destroying storage for room:")} ${room}`);
437
-
438
- // Always fire server-level onStorageDestroyed
439
- await Promise.resolve(listeners.onStorageDestroyed(event));
440
-
441
- await event.platform.persistence.deleteStorageState(room);
442
-
443
- logDebug(`${colors.blue("Destroyed storage for room:")} ${room}`);
444
- },
445
- async onMessage(event) {
446
- await Promise.resolve(listeners.onRoomMessage(event));
447
- },
448
- async onUserConnected(event) {
449
- await Promise.resolve(listeners.onUserConnected(event));
450
- },
451
- async onUserDisconnected(event) {
452
- await Promise.resolve(listeners.onUserDisconnected(event));
453
- },
454
- platform,
455
- roomContext,
456
- router: this._router,
457
- });
458
-
459
- this._logDebug(`${colors.blue("Created room:")} ${room}`);
460
-
461
- return newRoom;
462
- }
463
-
464
- public async createToken(
465
- params: JWTEncodeParams<InferIOAuthorizeUser<InferIOAuthorize<this>>, TPlatform>,
466
- ): Promise<string> {
467
- return await this._config.io.createToken(params);
468
- }
469
-
470
- private _getInitialStorage: GetInitialStorageFn<TContext> = (...args) => {
471
- const getInitialStorage =
472
- typeof this._config.getInitialStorage !== "string"
473
- ? (this._config.getInitialStorage ??
474
- ((() => null) as GetInitialStorageFn<TContext>))
475
- : ((() => null) as GetInitialStorageFn<TContext>);
476
-
477
- return getInitialStorage(...args);
478
- };
479
-
480
- private _getListeners(): BasePluvIOListeners<TPlatform, TAuthorize, TContext, TEvents> {
481
- return (this as any)._listeners;
482
- }
483
-
484
- private _logDebug(...data: any[]): void {
485
- if (this._config.debug) console.log(...data);
486
- }
487
- }
package/src/PubSub.ts DELETED
@@ -1,70 +0,0 @@
1
- import type { Subject } from "wonka";
2
- import { makeSubject, subscribe } from "wonka";
3
- import type { IOPubSubEventMessage } from "./AbstractPubSub";
4
- import { AbstractPubSub } from "./AbstractPubSub";
5
-
6
- export class PubSub extends AbstractPubSub {
7
- private _currentSubscriptionId: number = 0;
8
- // Map of roomName to subjects
9
- private _subjects = new Map<string, Subject<IOPubSubEventMessage<any>>>();
10
- // Map of roomName to subscription ids
11
- private _subscriptionsRefs = new Map<string, readonly number[]>();
12
- // Map of
13
- private _unsubscriptions = new Map<number, [roomName: string, unsubscribe: () => void]>();
14
-
15
- public async publish(roomName: string, payload: IOPubSubEventMessage<any>): Promise<void> {
16
- const subject = this._subjects.get(roomName);
17
-
18
- if (!subject) return;
19
-
20
- Promise.resolve(subject.next(payload));
21
- }
22
-
23
- public subscribe(
24
- roomName: string,
25
- onMessage: (message: IOPubSubEventMessage<any>) => void,
26
- ): Promise<number> {
27
- const id = this._currentSubscriptionId++;
28
- const refs = this._subscriptionsRefs.get(roomName) ?? [];
29
-
30
- const subject = makeSubject<IOPubSubEventMessage<any>>();
31
-
32
- this._subjects.set(roomName, subject);
33
- this._subscriptionsRefs.set(roomName, [...refs, id]);
34
-
35
- const unsubscribe = subscribe(onMessage)(subject.source).unsubscribe;
36
-
37
- this._unsubscriptions.set(id, [roomName, unsubscribe]);
38
-
39
- return Promise.resolve(id);
40
- }
41
-
42
- public unsubscribe(subscriptionId: number): void {
43
- const [roomName, unsubscribe] = this._unsubscriptions.get(subscriptionId) ?? [];
44
-
45
- if (!roomName || !unsubscribe) return;
46
-
47
- const refs = this._subscriptionsRefs.get(roomName);
48
-
49
- if (!refs) return;
50
-
51
- if (refs.length === 1) {
52
- this._subjects.delete(roomName);
53
- this._subscriptionsRefs.delete(roomName);
54
- this._unsubscriptions.delete(subscriptionId);
55
-
56
- return;
57
- }
58
-
59
- const index = refs.indexOf(subscriptionId);
60
-
61
- this._subscriptionsRefs.set(
62
- roomName,
63
- index === -1 ? refs : [...refs.slice(0, index), ...refs.slice(index + 1)],
64
- );
65
-
66
- unsubscribe();
67
-
68
- this._unsubscriptions.delete(subscriptionId);
69
- }
70
- }
package/src/authorize.ts DELETED
@@ -1,76 +0,0 @@
1
- import hkdf from "@panva/hkdf";
2
- import type { BaseUser } from "@pluv/types";
3
- import { EncryptJWT, jwtDecrypt } from "jose";
4
- import type { AbstractPlatform, InferInitContextType } from "./AbstractPlatform";
5
-
6
- const DEFAULT_MAX_AGE_MS = 60_000;
7
-
8
- export const getEncryptionKey = async (secret: string): Promise<Uint8Array> => {
9
- return await hkdf("sha256", secret, "", "Pluv.io Generated Encryption Key", 32);
10
- };
11
-
12
- export interface JWT<TUser extends BaseUser> {
13
- room: string;
14
- sub: string;
15
- user: TUser;
16
- }
17
-
18
- export type JWTEncodeParams<
19
- TUser extends BaseUser | null,
20
- TPlatform extends AbstractPlatform<any, any>,
21
- > = {
22
- maxAge?: number;
23
- room: string;
24
- user: TUser extends BaseUser ? TUser : "Error: Cannot create token without authorization!";
25
- } & InferInitContextType<TPlatform>;
26
-
27
- export interface AuthorizeParams {
28
- platform: AbstractPlatform<any, any>;
29
- secret: string;
30
- }
31
-
32
- export interface AuthorizeModule {
33
- decode: <TUser extends BaseUser>(jwt: string) => Promise<TUser | null>;
34
- encode: <TUser extends BaseUser, TPlatform extends AbstractPlatform<any, any>>(
35
- params: JWTEncodeParams<TUser, TPlatform>,
36
- ) => Promise<string>;
37
- }
38
-
39
- const now = () => (Date.now() / 1_000) | 0;
40
-
41
- export const authorize = (params: AuthorizeParams) => {
42
- const { platform, secret } = params;
43
-
44
- const encode = async <TUser extends BaseUser, TPlatform extends AbstractPlatform<any, any>>(
45
- encodeParams: JWTEncodeParams<TUser, TPlatform>,
46
- ): Promise<string> => {
47
- const { maxAge = DEFAULT_MAX_AGE_MS, room, user } = encodeParams;
48
-
49
- const encryptionSecret = await getEncryptionKey(secret);
50
-
51
- const token = await new EncryptJWT({
52
- room,
53
- sub: room ? `${room}|${user.id}` : user.id,
54
- user,
55
- })
56
- .setProtectedHeader({ alg: "dir", enc: "A256GCM" })
57
- .setIssuedAt()
58
- .setExpirationTime(now() + maxAge)
59
- .setJti(platform.randomUUID())
60
- .encrypt(encryptionSecret);
61
-
62
- return token.toString();
63
- };
64
-
65
- const decode = async <TUser extends BaseUser>(jwt: string): Promise<JWT<TUser> | null> => {
66
- const encryptionSecret = await getEncryptionKey(secret);
67
-
68
- const { payload } = await jwtDecrypt(jwt, encryptionSecret, {
69
- clockTolerance: 15,
70
- });
71
-
72
- return (payload as any) ?? null;
73
- };
74
-
75
- return { decode, encode };
76
- };
package/src/constants.ts DELETED
@@ -1,6 +0,0 @@
1
- export const GARBAGE_COLLECT_INTERVAL_MS = 60_000;
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;
5
- export const MAX_USER_SIZE_BYTES = 512;
6
- export const PING_TIMEOUT_MS = 30_000;
package/src/createIO.ts DELETED
@@ -1,55 +0,0 @@
1
- import type { CrdtLibraryType, NoopCrdtDocFactory } from "@pluv/crdt";
2
- import type { BaseUser } from "@pluv/types";
3
- import type { AbstractPlatform, InferInitContextType } from "./AbstractPlatform";
4
- import type { PluvIOConfig } from "./PluvIO";
5
- import { PluvIO } from "./PluvIO";
6
- import type { PluvContext, PluvIOAuthorize, PluvIOLimits } from "./types";
7
-
8
- export type CreateIOParams<
9
- TPlatform extends AbstractPlatform<any> = AbstractPlatform<any>,
10
- TContext extends Record<string, any> = {},
11
- TUser extends BaseUser | null = null,
12
- TCrdt extends CrdtLibraryType<any> = CrdtLibraryType<NoopCrdtDocFactory>,
13
- > = {
14
- authorize?: PluvIOAuthorize<TPlatform, TUser, InferInitContextType<TPlatform>>;
15
- context?: PluvContext<TPlatform, TContext>;
16
- crdt?: TCrdt;
17
- debug?: boolean;
18
- limits?: PluvIOLimits;
19
- platform: () => TPlatform;
20
- };
21
-
22
- export const createIO = <
23
- TPlatform extends AbstractPlatform<any> = AbstractPlatform<any>,
24
- TContext extends Record<string, any> = {},
25
- TUser extends BaseUser | null = null,
26
- TCrdt extends CrdtLibraryType<any> = CrdtLibraryType<NoopCrdtDocFactory>,
27
- >(
28
- params: CreateIOParams<TPlatform, TContext, TUser, TCrdt>,
29
- ): PluvIO<
30
- TPlatform,
31
- PluvIOAuthorize<TPlatform, TUser, InferInitContextType<TPlatform>>,
32
- TContext,
33
- TCrdt
34
- > => {
35
- const { authorize, context, crdt, debug, limits, platform } = params;
36
-
37
- return new PluvIO<
38
- TPlatform,
39
- PluvIOAuthorize<TPlatform, TUser, InferInitContextType<TPlatform>>,
40
- TContext,
41
- TCrdt
42
- >({
43
- authorize,
44
- context,
45
- crdt,
46
- debug,
47
- limits,
48
- platform,
49
- } as PluvIOConfig<
50
- TPlatform,
51
- PluvIOAuthorize<TPlatform, TUser, InferInitContextType<TPlatform>>,
52
- TContext,
53
- TCrdt
54
- >);
55
- };