@pluv/io 0.0.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/.eslintrc.js ADDED
@@ -0,0 +1,4 @@
1
+ module.exports = {
2
+ root: true,
3
+ extends: ["pluv"],
4
+ };
@@ -0,0 +1,17 @@
1
+
2
+ > @pluv/io@0.0.0 build /home/runner/work/pluv/pluv/packages/io
3
+ > tsup src/index.ts --format esm,cjs --dts
4
+
5
+ CLI Building entry: src/index.ts
6
+ CLI Using tsconfig: tsconfig.json
7
+ CLI tsup v6.5.0
8
+ CLI Target: es6
9
+ ESM Build start
10
+ CJS Build start
11
+ ESM dist/index.mjs 25.31 KB
12
+ ESM ⚡️ Build success in 112ms
13
+ CJS dist/index.js 27.11 KB
14
+ CJS ⚡️ Build success in 112ms
15
+ DTS Build start
16
+ DTS ⚡️ Build success in 2486ms
17
+ DTS dist/index.d.ts 12.29 KB
@@ -0,0 +1,257 @@
1
+ import { JsonObject, MaybePromise, IOEventMessage, EventRecord, InputZodLike, Id, IOLike, InferIOOutput, BaseUser, IOAuthorize, BaseIOAuthorize, InferEventMessage, InferIOInput, BaseIOEventRecord, InferIOAuthorize, InferIOAuthorizeUser, Spread, BaseClientEventRecord } from '@pluv/types';
2
+ export { BaseUser, EventMessage, EventRecord, IOEventMessage } from '@pluv/types';
3
+ import { YjsDoc } from '@pluv/crdt-yjs';
4
+
5
+ declare abstract class AbstractPersistance {
6
+ abstract addUser(room: string, connectionId: string, user: JsonObject | null): Promise<void>;
7
+ abstract deleteStorageState(room: string): Promise<void>;
8
+ abstract deleteUser(room: string, connectionId: string): Promise<void>;
9
+ abstract deleteUsers(room: string): Promise<void>;
10
+ abstract getStorageState(room: string): Promise<string | null>;
11
+ abstract getUser(room: string, connectionId: string): Promise<JsonObject | null>;
12
+ abstract getUsers(room: string): Promise<readonly (JsonObject | null)[]>;
13
+ abstract setStorageState(room: string, state: string): Promise<void>;
14
+ }
15
+
16
+ type AbstractEvent = {};
17
+ type AbstractCloseEvent = AbstractEvent & {
18
+ readonly code: number;
19
+ readonly reason: string;
20
+ };
21
+ type AbstractMessageEvent<T = any> = AbstractEvent & {
22
+ readonly data: T;
23
+ };
24
+ type AbstractErrorEvent = AbstractEvent & {
25
+ error: unknown;
26
+ message: string;
27
+ };
28
+ interface AbstractEventMap {
29
+ close: AbstractCloseEvent;
30
+ message: AbstractMessageEvent;
31
+ error: AbstractErrorEvent;
32
+ }
33
+ type EventType = keyof AbstractEventMap;
34
+ interface AbstractWebSocketHandleErrorParams {
35
+ error: unknown;
36
+ message?: string;
37
+ session?: WebSocketSession;
38
+ }
39
+ type AbstractListener<TType extends keyof AbstractEventMap> = (event: AbstractEventMap[TType]) => MaybePromise<void>;
40
+ interface AbstractWebSocketConfig {
41
+ pubSub?: AbstractPubSub;
42
+ room: string;
43
+ }
44
+ declare abstract class AbstractWebSocket {
45
+ /** The connection is not yet open. */
46
+ readonly CONNECTING = 0;
47
+ /** The connection is open and ready to communicate. */
48
+ readonly OPEN = 1;
49
+ /** The connection is in the process of closing. */
50
+ readonly CLOSING = 2;
51
+ /** The connection is closed. */
52
+ readonly CLOSED = 3;
53
+ pubSub?: AbstractPubSub;
54
+ room: string;
55
+ abstract get readyState(): 0 | 1 | 2 | 3;
56
+ constructor(config: AbstractWebSocketConfig);
57
+ /**
58
+ * TODO
59
+ * @description Return an unsubscribe method to remove the event-listener.
60
+ * This is preferred over adding an explicit abstract removeEventListener
61
+ * method, because the implementing class might have to transform the
62
+ * listener, and removing the same listener might be complicated as a
63
+ * result.
64
+ * @author leedavidcs
65
+ * @date August 28, 2022
66
+ */
67
+ abstract addEventListener<TType extends EventType>(type: TType, handler: AbstractListener<TType>): void;
68
+ abstract close(code?: number | undefined, reason?: string | undefined): void;
69
+ abstract initialize(): Promise<() => void>;
70
+ abstract send(message: ArrayBuffer | ArrayBufferView | string): void;
71
+ abstract terminate(): void;
72
+ handleError(params: AbstractWebSocketHandleErrorParams): void;
73
+ sendMessage<TMessage extends IOEventMessage<any> = IOEventMessage<any>>(data: TMessage): void;
74
+ }
75
+
76
+ declare global {
77
+ var console: {
78
+ log: (...data: any[]) => void;
79
+ };
80
+ }
81
+ interface EventConfig<TContext extends JsonObject = {}, TData extends JsonObject = {}, TResult extends EventRecord<string, any> = {}> {
82
+ input?: InputZodLike<TData>;
83
+ options?: SendMessageOptions;
84
+ resolver: EventResolver<TContext, TData, TResult>;
85
+ }
86
+ type EventResolver<TContext extends JsonObject = {}, TData extends JsonObject = {}, TResult extends EventRecord<string, any> = {}> = (data: TData, context: EventResolverContext<TContext>) => MaybePromise<TResult | void>;
87
+ interface EventResolverContext<TContext extends JsonObject = {}> {
88
+ context: TContext;
89
+ doc: YjsDoc<any>;
90
+ room: string;
91
+ /**
92
+ * !HACK
93
+ * @description Session should only not exist when invoking the event as a
94
+ * "sync" event on another machine where the session doesn't exist. There must
95
+ * be a better way to handle this, but going to make this nullable for ease
96
+ * for now.
97
+ *
98
+ * `session` should not be referenced most of the time anyhow (outside of
99
+ * internal to this library).
100
+ * @author leedavidcs
101
+ * @date December 25, 2022
102
+ */
103
+ session: WebSocketSession | null;
104
+ sessions: Map<string, WebSocketSession>;
105
+ }
106
+ type InferEventConfig<TContext extends JsonObject = {}, TInput extends EventRecord<string, any> = {}, TOutput extends EventRecord<string, any> = {}> = {
107
+ [P in keyof TInput]: P extends string ? Id<EventConfig<TContext, TInput[P], TOutput>> : never;
108
+ };
109
+ type SendMessageOptions = {
110
+ type?: "broadcast";
111
+ sessionIds?: readonly string[];
112
+ } | {
113
+ type: "self";
114
+ } | {
115
+ type: "sync";
116
+ };
117
+ interface WebSocketSessionTimers {
118
+ ping: number;
119
+ }
120
+ interface WebSocketSession {
121
+ id: string;
122
+ presence: JsonObject | null;
123
+ quit: boolean;
124
+ room: string;
125
+ timers: WebSocketSessionTimers;
126
+ webSocket: AbstractWebSocket;
127
+ user: JsonObject | null;
128
+ }
129
+
130
+ type IOPubSubEventMessage<TIO extends IOLike, TEvent extends keyof InferIOOutput<TIO> = keyof InferIOOutput<TIO>> = IOEventMessage<TIO, TEvent> & {
131
+ options?: SendMessageOptions;
132
+ };
133
+ declare abstract class AbstractPubSub {
134
+ abstract publish(roomName: string, payload: IOPubSubEventMessage<any>): Promise<void>;
135
+ abstract subscribe(roomName: string, onMessage: (message: IOPubSubEventMessage<any>) => void): Promise<number>;
136
+ abstract unsubscribe(subscriptionId: number): void;
137
+ }
138
+
139
+ type InferWebSocketType<TPlatform extends AbstractPlatform<any>> = TPlatform extends AbstractPlatform<infer IWebSocket> ? IWebSocket : never;
140
+ type AbstractPlatformConfig = {
141
+ persistance?: undefined;
142
+ pubSub?: undefined;
143
+ } | {
144
+ persistance: AbstractPersistance;
145
+ pubSub: AbstractPubSub;
146
+ };
147
+ interface ConvertWebSocketConfig {
148
+ room: string;
149
+ }
150
+ declare abstract class AbstractPlatform<TWebSocket = any> {
151
+ persistance: AbstractPersistance;
152
+ pubSub: AbstractPubSub;
153
+ constructor(config?: AbstractPlatformConfig);
154
+ abstract convertWebSocket(webSocket: TWebSocket, config: ConvertWebSocketConfig): AbstractWebSocket;
155
+ abstract parseData(data: string | ArrayBuffer): Record<string, any>;
156
+ abstract randomUUID(): string;
157
+ }
158
+
159
+ interface JWT<TUser extends BaseUser> {
160
+ room: string;
161
+ sub: string;
162
+ user: TUser;
163
+ }
164
+ interface JWTEncodeParams<TUser extends BaseUser> {
165
+ maxAge?: number;
166
+ room: string;
167
+ user: TUser;
168
+ }
169
+ interface AuthorizeParams {
170
+ platform: AbstractPlatform;
171
+ secret: string;
172
+ }
173
+ interface AuthorizeModule {
174
+ decode: <TUser extends BaseUser>(jwt: string) => Promise<TUser | null>;
175
+ encode: <TUser extends BaseUser>(params: JWTEncodeParams<TUser>) => Promise<string>;
176
+ }
177
+
178
+ type BroadcastMessage<TIO extends IORoom<any, any, any, any, any>> = InferEventMessage<InferIOInput<TIO>> | InferEventMessage<BaseIOEventRecord<InferIOAuthorize<TIO>>>;
179
+ interface IORoomConfig<TPlatform extends AbstractPlatform<any> = AbstractPlatform<any>, TAuthorize extends IOAuthorize<any, any> = BaseIOAuthorize, TContext extends JsonObject = {}, TInput extends EventRecord<string, any> = {}, TOutput extends EventRecord<string, any> = {}> {
180
+ authorize?: TAuthorize;
181
+ context: TContext;
182
+ debug: boolean;
183
+ events: InferEventConfig<TContext, TInput, TOutput>;
184
+ onDestroy?: () => void;
185
+ platform: TPlatform;
186
+ }
187
+ interface WebsocketRegisterOptions {
188
+ token?: string;
189
+ }
190
+ declare class IORoom<TPlatform extends AbstractPlatform<any> = AbstractPlatform<any>, TAuthorize extends IOAuthorize<any, any> = BaseIOAuthorize, TContext extends JsonObject = {}, TInput extends EventRecord<string, any> = {}, TOutput extends EventRecord<string, any> = {}> implements IOLike<TAuthorize, TInput, TOutput> {
191
+ private readonly _context;
192
+ private readonly _debug;
193
+ private readonly _platform;
194
+ private _doc;
195
+ private _listeners;
196
+ private _sessions;
197
+ private _uninitialize;
198
+ readonly _authorize: TAuthorize | null;
199
+ readonly _events: InferEventConfig<TContext, TInput, TOutput>;
200
+ readonly room: string;
201
+ constructor(room: string, config: IORoomConfig<TPlatform, TAuthorize, TContext, TInput, TOutput>);
202
+ broadcast(message: BroadcastMessage<this>): Promise<void>;
203
+ register(webSocket: InferWebSocketType<TPlatform>, options?: WebsocketRegisterOptions): Promise<void>;
204
+ private _broadcast;
205
+ private _emitQuitters;
206
+ private _emitRegistered;
207
+ private _emitStorageReceived;
208
+ private _emitUserJoined;
209
+ private _getAuthorizedUser;
210
+ private _getSessionsSize;
211
+ private _getEventConfig;
212
+ private _initialize;
213
+ private _logDebug;
214
+ private _parseMessage;
215
+ private _resolveMessage;
216
+ private _sendMessage;
217
+ private _sendBroadcastMessage;
218
+ private _sendSelfMessage;
219
+ private _sendSyncMessage;
220
+ }
221
+
222
+ type InferIOContext<TIO extends PluvIO<any, any, any, any, any>> = TIO extends PluvIO<any, any, infer IContext, any, any> ? IContext : never;
223
+ type InferIOPlatform<TIO extends PluvIO<any, any, any, any>> = TIO extends PluvIO<infer IPlatform, any, any, any, any> ? IPlatform : never;
224
+ type InferIORoom<TIO extends PluvIO<any, any, any, any>> = TIO extends PluvIO<infer IPlatform, infer IAuthorize, infer IContext, infer IInput, infer IOutput> ? IORoom<IPlatform, IAuthorize, IContext, IInput, IOutput> : never;
225
+ interface PluvIOConfig<TPlatform extends AbstractPlatform<any> = AbstractPlatform<any>, TAuthorize extends IOAuthorize<any, any> | null = null, TContext extends JsonObject = {}, TInput extends EventRecord<string, any> = {}, TOutput extends EventRecord<string, any> = {}> {
226
+ authorize?: TAuthorize;
227
+ context?: TContext;
228
+ debug?: boolean;
229
+ events?: InferEventConfig<TContext, TInput, TOutput>;
230
+ platform: TPlatform;
231
+ room?: string;
232
+ }
233
+ declare class PluvIO<TPlatform extends AbstractPlatform<any> = AbstractPlatform<any>, TAuthorize extends IOAuthorize<any, any> = BaseIOAuthorize, TContext extends JsonObject = {}, TInput extends EventRecord<string, any> = {}, TOutput extends EventRecord<string, any> = {}> implements IOLike<TAuthorize, TInput, TOutput> {
234
+ readonly _authorize: TAuthorize | null;
235
+ readonly _debug: boolean;
236
+ readonly _events: InferEventConfig<TContext, TInput, TOutput>;
237
+ readonly _platform: TPlatform;
238
+ readonly room: string | null;
239
+ private _context;
240
+ private _rooms;
241
+ constructor(options: PluvIOConfig<TPlatform, TAuthorize, TContext, TInput, TOutput>);
242
+ createToken(params: JWTEncodeParams<InferIOAuthorizeUser<InferIOAuthorize<this>>>): Promise<string>;
243
+ event<TEvent extends string, TData extends JsonObject = {}, TResult extends EventRecord<string, any> = {}>(event: TEvent, config: EventConfig<TContext, TData, TResult>): PluvIO<TPlatform, TAuthorize, TContext, Spread<[TInput, EventRecord<TEvent, TData>]>, Spread<[TOutput, TResult]>>;
244
+ getRoom(room: string): IORoom<TPlatform, TAuthorize, TContext, TInput, TOutput>;
245
+ static merge<TIO1 extends PluvIO, TIO2 extends PluvIO>(first: TIO1, second: TIO2): PluvIO<InferIOPlatform<TIO1>, InferIOAuthorize<TIO1>, InferIOContext<TIO1>, Spread<[InferIOInput<TIO1>, InferIOInput<TIO2>]>, Spread<[InferIOOutput<TIO1>, InferIOOutput<TIO2>]>>;
246
+ private _logDebug;
247
+ }
248
+
249
+ interface CreateIOParams<TPlatform extends AbstractPlatform<any> = AbstractPlatform<any>, TContext extends JsonObject = {}, TAuthorizeUser extends BaseUser = BaseUser, TAuthorizeRequired extends boolean = false> {
250
+ authorize?: IOAuthorize<TAuthorizeUser, TAuthorizeRequired>;
251
+ context?: TContext;
252
+ debug?: boolean;
253
+ platform: TPlatform;
254
+ }
255
+ declare const createIO: <TPlatform extends AbstractPlatform<any> = AbstractPlatform<any>, TContext extends JsonObject = {}, TAuthorizeUser extends BaseUser = BaseUser, TAuthorizeRequired extends boolean = false>(params: CreateIOParams<TPlatform, TContext, TAuthorizeUser, TAuthorizeRequired>) => PluvIO<TPlatform, IOAuthorize<TAuthorizeUser, TAuthorizeRequired>, TContext, BaseClientEventRecord, BaseIOEventRecord<IOAuthorize<TAuthorizeUser, TAuthorizeRequired>>>;
256
+
257
+ export { AbstractCloseEvent, AbstractErrorEvent, AbstractEvent, AbstractEventMap, AbstractListener, AbstractMessageEvent, AbstractPersistance, AbstractPlatform, AbstractPubSub, AbstractWebSocket, AbstractWebSocketConfig, AbstractWebSocketHandleErrorParams, AuthorizeModule, AuthorizeParams, ConvertWebSocketConfig, IOPubSubEventMessage, IORoom, InferIORoom, InferWebSocketType, JWT, JWTEncodeParams, PluvIO, createIO };