@pluv/io 0.0.0-experimental-20250527040415

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/index.ts ADDED
@@ -0,0 +1,54 @@
1
+ export type { BaseUser, EventMessage, EventRecord, IOEventMessage } from "@pluv/types";
2
+ export { AbstractPersistence } from "./AbstractPersistence";
3
+ export { AbstractPlatform } from "./AbstractPlatform";
4
+ export type {
5
+ AbstractPlatformConfig,
6
+ ConvertWebSocketConfig,
7
+ InferInitContextType,
8
+ InferPlatformWebSocketType,
9
+ InferRoomContextType,
10
+ } from "./AbstractPlatform";
11
+ export { AbstractPubSub } from "./AbstractPubSub";
12
+ export type { IOPubSubEventMessage } from "./AbstractPubSub";
13
+ export { AbstractWebSocket } from "./AbstractWebSocket";
14
+ export type {
15
+ AbstractCloseEvent,
16
+ AbstractErrorEvent,
17
+ AbstractEvent,
18
+ AbstractEventMap,
19
+ AbstractListener,
20
+ AbstractMessageEvent,
21
+ AbstractWebSocketConfig,
22
+ AbstractWebSocketHandleErrorParams,
23
+ } from "./AbstractWebSocket";
24
+ export { authorize } from "./authorize";
25
+ export type { AuthorizeModule, AuthorizeParams, JWT, JWTEncodeParams } from "./authorize";
26
+ export { createIO } from "./createIO";
27
+ export type { CreateIOParams } from "./createIO";
28
+ export type { IORoom } from "./IORoom";
29
+ export { PluvIO } from "./PluvIO";
30
+ export type { PluvIOConfig, ServerConfig } from "./PluvIO";
31
+ export { PluvProcedure } from "./PluvProcedure";
32
+ export type { PluvProcedureConfig } from "./PluvProcedure";
33
+ export { PluvRouter } from "./PluvRouter";
34
+ export type { MergedRouter, PluvRouterEventConfig } from "./PluvRouter";
35
+ export { PluvServer } from "./PluvServer";
36
+ export type { CreateRoomOptions, InferIORoom, PluvServerConfig } from "./PluvServer";
37
+ export type {
38
+ CrdtLibraryType,
39
+ GetInitialStorageFn,
40
+ HandleMode,
41
+ IORoomListenerEvent,
42
+ IORoomMessageEvent,
43
+ IOStorageUpdatedEvent,
44
+ IOUserConnectedEvent,
45
+ IOUserDisconnectedEvent,
46
+ PlatformConfig,
47
+ PluvContext,
48
+ PluvIOAuthorize,
49
+ PluvIOLimits,
50
+ PluvIOListeners,
51
+ WebSocketRegistrationMode,
52
+ WebSocketSerializedState,
53
+ WebSocketSession,
54
+ } from "./types";
package/src/types.ts ADDED
@@ -0,0 +1,283 @@
1
+ import type { AbstractCrdtDocFactory } from "@pluv/crdt";
2
+ import type {
3
+ BaseUser,
4
+ CrdtDocLike,
5
+ EventRecord,
6
+ IOAuthorize,
7
+ Id,
8
+ InferEventMessage,
9
+ InferEventsOutput,
10
+ InferIOAuthorizeUser,
11
+ InputZodLike,
12
+ JsonObject,
13
+ Maybe,
14
+ MaybePromise,
15
+ UndefinedProps,
16
+ } from "@pluv/types";
17
+ import type {
18
+ AbstractPlatform,
19
+ InferInitContextType,
20
+ InferPlatformWebSocketSource,
21
+ InferPlatformWebSocketType,
22
+ InferRoomContextType,
23
+ } from "./AbstractPlatform";
24
+ import type { AbstractWebSocket } from "./AbstractWebSocket";
25
+ import type { PluvRouter, PluvRouterEventConfig } from "./PluvRouter";
26
+
27
+ export type PluvContext<TPlatform extends AbstractPlatform, TContext extends Record<string, any>> =
28
+ | TContext
29
+ | ((params: InferRoomContextType<TPlatform>) => TContext);
30
+
31
+ export interface CrdtLibraryType {
32
+ doc: (value: any) => AbstractCrdtDocFactory<any, any>;
33
+ kind: "loro" | "yjs";
34
+ }
35
+
36
+ export type EventResolverKind = "broadcast" | "self" | "sync";
37
+
38
+ export type EventResolver<
39
+ TKind extends EventResolverKind = EventResolverKind,
40
+ TPlatform extends AbstractPlatform = AbstractPlatform,
41
+ TAuthorize extends IOAuthorize<any, InferInitContextType<TPlatform>> | null = null,
42
+ TContext extends Record<string, any> = {},
43
+ TInput extends JsonObject = {},
44
+ TOutput extends EventRecord<string, any> = {},
45
+ > = (
46
+ data: TInput,
47
+ context: EventResolverContext<TKind, TPlatform, TAuthorize, TContext>,
48
+ ) => MaybePromise<TOutput | void>;
49
+
50
+ export interface EventResolverContext<
51
+ TKind extends EventResolverKind = EventResolverKind,
52
+ TPlatform extends AbstractPlatform = AbstractPlatform,
53
+ TAuthorize extends IOAuthorize<any, InferInitContextType<TPlatform>> | null = null,
54
+ TContext extends Record<string, any> = {},
55
+ > {
56
+ context: TContext;
57
+ doc: CrdtDocLike<any, any>;
58
+ garbageCollect: () => Promise<void>;
59
+ platform: TPlatform;
60
+ presence: JsonObject | null;
61
+ room: string;
62
+ session: TKind extends "sync"
63
+ ? WebSocketSession<TAuthorize> | null
64
+ : WebSocketSession<TAuthorize>;
65
+ sessions: readonly WebSocketSession<TAuthorize>[];
66
+ time: number;
67
+ }
68
+
69
+ export type SendMessageOptions =
70
+ | { type?: "broadcast"; sessionIds?: readonly string[] }
71
+ | { type: "self" }
72
+ | { type: "sync" };
73
+
74
+ export interface WebSocketSessionTimers {
75
+ ping: number;
76
+ presence: number | null;
77
+ }
78
+
79
+ export interface WebSocketSerializedState {
80
+ presence: JsonObject | null;
81
+ quit: boolean;
82
+ room: string;
83
+ timers: WebSocketSessionTimers;
84
+ }
85
+
86
+ export type WebSocketSession<TAuthorize extends IOAuthorize<any, any> | null = null> =
87
+ WebSocketSerializedState & {
88
+ id: string;
89
+ user: InferIOAuthorizeUser<TAuthorize>;
90
+ webSocket: AbstractWebSocket;
91
+ };
92
+
93
+ export type MergeEventRecords<
94
+ TEventRecords extends EventRecord<string, any>[],
95
+ TRoot extends EventRecord<string, any> = {},
96
+ > = TEventRecords extends [
97
+ infer IHead extends EventRecord<string, any>,
98
+ ...infer ITail extends EventRecord<string, any>[],
99
+ ]
100
+ ? MergeEventRecords<
101
+ ITail,
102
+ Omit<TRoot, keyof IHead> & {
103
+ [P in keyof IHead]: TRoot extends Record<P, any> ? TRoot[P] | IHead[P] : IHead[P];
104
+ }
105
+ >
106
+ : Id<TRoot>;
107
+
108
+ export type GetInitialStorageEvent<TContext extends Record<string, any>> = {
109
+ context: TContext;
110
+ room: string;
111
+ };
112
+
113
+ export type GetInitialStorageFn<TContext extends Record<string, any>> = (
114
+ event: GetInitialStorageEvent<TContext>,
115
+ ) => MaybePromise<Maybe<string>>;
116
+
117
+ export type HandleMode = "io" | "fetch";
118
+ export type WebSocketRegistrationMode = "attached" | "detached";
119
+
120
+ export interface PlatformConfig {
121
+ authorize: {
122
+ secret?: boolean;
123
+ };
124
+ requireAuth?: boolean;
125
+ handleMode: HandleMode;
126
+ registrationMode: WebSocketRegistrationMode;
127
+ listeners: {
128
+ onRoomDeleted?: boolean;
129
+ onRoomMessage?: boolean;
130
+ onStorageUpdated?: boolean;
131
+ onUserConnected?: boolean;
132
+ onUserDisconnected?: boolean;
133
+ };
134
+ router?: boolean;
135
+ }
136
+
137
+ export type ResolvedPluvIOAuthorize<
138
+ TPlatform extends AbstractPlatform<any, any, any, any>,
139
+ TUser extends BaseUser = any,
140
+ > = { user: InputZodLike<TUser> } & UndefinedProps<
141
+ { secret?: string },
142
+ Exclude<"secret", InferPlatformAuthorizeProperties<TPlatform>>
143
+ >;
144
+
145
+ export type PluvIOAuthorize<
146
+ TPlatform extends AbstractPlatform<any, any, any, any>,
147
+ TUser extends BaseUser | null = any,
148
+ TContext extends Record<string, unknown> = {},
149
+ > =
150
+ | (TUser extends BaseUser ? ResolvedPluvIOAuthorize<TPlatform, TUser> : null)
151
+ | ((
152
+ context: TContext,
153
+ ) => TUser extends BaseUser ? ResolvedPluvIOAuthorize<TPlatform, TUser> : null);
154
+
155
+ export interface PluvIOLimits {
156
+ /**
157
+ * @description Maximum size of presence object in bytes
158
+ */
159
+ presenceMaxSize?: number | null;
160
+ /**
161
+ * @description Maximum size of storage state in bytes
162
+ */
163
+ storageMaxSize?: number | null;
164
+ /**
165
+ * @description Maximum length of user id in characters
166
+ */
167
+ userIdMaxLength?: number | null;
168
+ /**
169
+ * @description Maximum size of user object in bytes
170
+ */
171
+ userMaxSize?: number | null;
172
+ }
173
+
174
+ export type BasePluvIOListeners<
175
+ TPlatform extends AbstractPlatform<any, any, any, any>,
176
+ TAuthorize extends PluvIOAuthorize<TPlatform, any, InferInitContextType<TPlatform>> | null,
177
+ TContext extends Record<string, any>,
178
+ TEvents extends PluvRouterEventConfig<TPlatform, TAuthorize, TContext>,
179
+ > = {
180
+ onRoomDeleted: (event: IORoomListenerEvent<TPlatform, TContext>) => void;
181
+ onRoomMessage: (event: IORoomMessageEvent<TPlatform, TAuthorize, TContext, TEvents>) => void;
182
+ onStorageUpdated: (event: IOStorageUpdatedEvent<TPlatform, TAuthorize, TContext>) => void;
183
+ onUserConnected: (event: IOUserConnectedEvent<TPlatform, TAuthorize, TContext>) => void;
184
+ onUserDisconnected: (event: IOUserDisconnectedEvent<TPlatform, TAuthorize, TContext>) => void;
185
+ };
186
+
187
+ export type PluvIOListeners<
188
+ TPlatform extends AbstractPlatform<any, any, any, any>,
189
+ TAuthorize extends PluvIOAuthorize<TPlatform, any, InferInitContextType<TPlatform>> | null,
190
+ TContext extends Record<string, any>,
191
+ TEvents extends PluvRouterEventConfig<TPlatform, TAuthorize, TContext>,
192
+ > = UndefinedProps<
193
+ BasePluvIOListeners<TPlatform, TAuthorize, TContext, TEvents>,
194
+ Exclude<
195
+ keyof BasePluvIOListeners<TPlatform, TAuthorize, TContext, TEvents>,
196
+ InferPlatformListeners<TPlatform>
197
+ >
198
+ >;
199
+
200
+ export type PluvIORouter<
201
+ TPlatform extends AbstractPlatform<any, any, any, any>,
202
+ TAuthorize extends PluvIOAuthorize<TPlatform, any, InferInitContextType<TPlatform>> | null,
203
+ TContext extends Record<string, any>,
204
+ TEvents extends PluvRouterEventConfig<TPlatform, TAuthorize, TContext>,
205
+ > =
206
+ InferPlatformRouter<TPlatform> extends true
207
+ ? { router?: PluvRouter<TPlatform, TAuthorize, TContext, TEvents> }
208
+ : { router?: undefined };
209
+
210
+ export type InferPlatformConfig<TPlatform extends AbstractPlatform<any, any, any, any>> =
211
+ TPlatform extends AbstractPlatform<any, any, any, infer IConfig> ? IConfig : never;
212
+
213
+ export type InferPlatformAuthorizeProperties<
214
+ TPlatform extends AbstractPlatform<any, any, any, any>,
215
+ > = keyof {
216
+ [P in keyof PlatformConfig["authorize"] as InferPlatformConfig<TPlatform>["authorize"][P] extends
217
+ | true
218
+ | undefined
219
+ ? P
220
+ : never]: true;
221
+ };
222
+
223
+ export type InferPlatformListeners<TPlatform extends AbstractPlatform<any, any, any, any>> = keyof {
224
+ [P in keyof PlatformConfig["listeners"] as InferPlatformConfig<TPlatform>["listeners"][P] extends
225
+ | true
226
+ | undefined
227
+ ? P
228
+ : never]: true;
229
+ };
230
+
231
+ export type InferPlatformRouter<TPlatform extends AbstractPlatform<any, any, any, any>> =
232
+ InferPlatformConfig<TPlatform>["router"];
233
+
234
+ export type IORoomListenerEvent<
235
+ TPlatform extends AbstractPlatform<any, any, any, any>,
236
+ TContext extends Record<string, any>,
237
+ > = {
238
+ context: TContext;
239
+ encodedState: string | null;
240
+ platform: TPlatform;
241
+ room: string;
242
+ };
243
+
244
+ export type IORoomMessageEvent<
245
+ TPlatform extends AbstractPlatform<any>,
246
+ TAuthorize extends PluvIOAuthorize<TPlatform, any, InferInitContextType<TPlatform>> | null,
247
+ TContext extends Record<string, any>,
248
+ TEvents extends PluvRouterEventConfig<TPlatform, TAuthorize, TContext>,
249
+ > = IORoomListenerEvent<TPlatform, TContext> & {
250
+ message: InferEventMessage<InferEventsOutput<TEvents>, keyof InferEventsOutput<TEvents>>;
251
+ user?: InferIOAuthorizeUser<TAuthorize>;
252
+ webSocket?: InferPlatformWebSocketSource<TPlatform>;
253
+ };
254
+
255
+ export type IOStorageUpdatedEvent<
256
+ TPlatform extends AbstractPlatform<any>,
257
+ TAuthorize extends IOAuthorize<any, InferInitContextType<TPlatform>> | null,
258
+ TContext extends Record<string, any>,
259
+ > = IORoomListenerEvent<TPlatform, TContext> & {
260
+ user?: InferIOAuthorizeUser<TAuthorize>;
261
+ webSocket?: InferPlatformWebSocketSource<TPlatform>;
262
+ };
263
+
264
+ export type IOUserConnectedEvent<
265
+ TPlatform extends AbstractPlatform<any>,
266
+ TAuthorize extends IOAuthorize<any, InferInitContextType<TPlatform>> | null,
267
+ TContext extends Record<string, any>,
268
+ > = IORoomListenerEvent<TPlatform, TContext> & {
269
+ user?: InferIOAuthorizeUser<TAuthorize>;
270
+ webSocket?: InferPlatformWebSocketSource<TPlatform>;
271
+ };
272
+
273
+ export type IOUserDisconnectedEvent<
274
+ TPlatform extends AbstractPlatform<any>,
275
+ TAuthorize extends IOAuthorize<any, InferInitContextType<TPlatform>> | null,
276
+ TContext extends Record<string, any>,
277
+ > = IORoomListenerEvent<TPlatform, TContext> & {
278
+ user?: InferIOAuthorizeUser<TAuthorize>;
279
+ };
280
+
281
+ export type WebSocketType<TPlatform extends AbstractPlatform> =
282
+ | InferPlatformWebSocketType<TPlatform>
283
+ | InferPlatformWebSocketSource<TPlatform>;
@@ -0,0 +1,2 @@
1
+ export { oneLine } from "./oneLine";
2
+ export { pickBy } from "./pickBy";
@@ -0,0 +1,7 @@
1
+ export const oneLine = (strings: TemplateStringsArray, ...values: unknown[]): string => {
2
+ return strings
3
+ .map((str) => str.replace(/\s+/g, " "))
4
+ .reduce((acc, str, i) => acc + str + (i < values.length ? values[i] : ""), "")
5
+ .replace(/\s+/g, " ")
6
+ .trim();
7
+ };
@@ -0,0 +1,16 @@
1
+ export const pickBy = <T extends Record<string, any>>(
2
+ obj: T,
3
+ by: (value: T[keyof T]) => boolean,
4
+ ): Partial<T> => {
5
+ const result: Partial<T> = {};
6
+ const keys: (keyof T)[] = Object.keys(obj);
7
+
8
+ for (let i = 0; i < keys.length; ++i) {
9
+ const key = keys[i];
10
+ const value = obj[key];
11
+
12
+ if (by(value)) result[key] = value;
13
+ }
14
+
15
+ return result;
16
+ };
@@ -0,0 +1,2 @@
1
+ // Generated by genversion.
2
+ export const version = '2.2.4'
package/src/version.ts ADDED
@@ -0,0 +1,3 @@
1
+ // eslint-disable-next-line @typescript-eslint/ban-ts-comment
2
+ // @ts-ignore
3
+ export { version as __PLUV_VERSION } from "./version.generated";
package/tsconfig.json ADDED
@@ -0,0 +1,9 @@
1
+ {
2
+ "extends": "@pluv/tsconfig/library.json",
3
+ "include": ["next-env.d.ts", "src/*.ts"],
4
+ "exclude": ["node_modules"],
5
+ "compilerOptions": {
6
+ "lib": ["esnext", "dom"],
7
+ "types": [],
8
+ }
9
+ }