@pluv/io 0.33.0 → 0.34.1

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 CHANGED
@@ -1,18 +1,9 @@
1
1
  import type { AbstractCrdtDocFactory } from "@pluv/crdt";
2
2
  import { noop } from "@pluv/crdt";
3
- import type {
4
- BaseIOAuthorize,
5
- IOAuthorize,
6
- IOLike,
7
- Id,
8
- InferIOAuthorize,
9
- InferIOAuthorizeUser,
10
- JsonObject,
11
- Maybe,
12
- } from "@pluv/types";
3
+ import type { IOLike, Id, InferIOAuthorize, InferIOAuthorizeUser, JsonObject, Maybe } from "@pluv/types";
13
4
  import colors from "kleur";
14
5
  import type { AbstractPlatform, InferInitContextType, InferRoomContextType } from "./AbstractPlatform";
15
- import type { IORoomListeners } from "./IORoom";
6
+ import type { IORoomListeners, WebsocketRegisterConfig } from "./IORoom";
16
7
  import { IORoom } from "./IORoom";
17
8
  import { PluvProcedure } from "./PluvProcedure";
18
9
  import type { PluvRouterEventConfig } from "./PluvRouter";
@@ -20,7 +11,14 @@ import { PluvRouter } from "./PluvRouter";
20
11
  import type { JWTEncodeParams } from "./authorize";
21
12
  import { authorize } from "./authorize";
22
13
  import { PING_TIMEOUT_MS } from "./constants";
23
- import type { GetInitialStorageFn, PluvContext, PluvIOListeners } from "./types";
14
+ import type {
15
+ BasePluvIOListeners,
16
+ GetInitialStorageFn,
17
+ PluvContext,
18
+ PluvIOAuthorize,
19
+ PluvIOListeners,
20
+ ResolvedPluvIOAuthorize,
21
+ } from "./types";
24
22
  import { __PLUV_VERSION } from "./version";
25
23
 
26
24
  export type InferIORoom<TServer extends PluvServer<any, any, any, any>> =
@@ -30,7 +28,7 @@ export type InferIORoom<TServer extends PluvServer<any, any, any, any>> =
30
28
 
31
29
  export type PluvServerConfig<
32
30
  TPlatform extends AbstractPlatform<any> = AbstractPlatform<any>,
33
- TAuthorize extends IOAuthorize<any, any, InferInitContextType<TPlatform>> = BaseIOAuthorize,
31
+ TAuthorize extends PluvIOAuthorize<TPlatform, any, any, InferInitContextType<TPlatform>> = any,
34
32
  TContext extends Record<string, any> = {},
35
33
  TEvents extends PluvRouterEventConfig<TPlatform, TAuthorize, TContext> = {},
36
34
  > = Partial<PluvIOListeners<TPlatform, TAuthorize, TContext, TEvents>> & {
@@ -45,7 +43,7 @@ export type PluvServerConfig<
45
43
 
46
44
  type BaseCreateRoomOptions<
47
45
  TPlatform extends AbstractPlatform<any>,
48
- TAuthorize extends IOAuthorize<any, any, InferInitContextType<TPlatform>>,
46
+ TAuthorize extends PluvIOAuthorize<TPlatform, any, any, InferInitContextType<TPlatform>>,
49
47
  TContext extends Record<string, any>,
50
48
  TEvents extends PluvRouterEventConfig<TPlatform, TAuthorize, TContext>,
51
49
  > = Partial<IORoomListeners<TPlatform, TAuthorize, TContext, TEvents>> & {
@@ -54,7 +52,7 @@ type BaseCreateRoomOptions<
54
52
 
55
53
  export type CreateRoomOptions<
56
54
  TPlatform extends AbstractPlatform<any>,
57
- TAuthorize extends IOAuthorize<any, any, InferInitContextType<TPlatform>>,
55
+ TAuthorize extends PluvIOAuthorize<TPlatform, any, any, InferInitContextType<TPlatform>>,
58
56
  TContext extends Record<string, any>,
59
57
  TEvents extends PluvRouterEventConfig<TPlatform, TAuthorize, TContext>,
60
58
  > = keyof InferRoomContextType<TPlatform> extends never
@@ -63,7 +61,7 @@ export type CreateRoomOptions<
63
61
 
64
62
  export class PluvServer<
65
63
  TPlatform extends AbstractPlatform<any> = AbstractPlatform<any>,
66
- TAuthorize extends IOAuthorize<any, any, InferInitContextType<TPlatform>> = BaseIOAuthorize,
64
+ TAuthorize extends PluvIOAuthorize<TPlatform, any, any, InferInitContextType<TPlatform>> = any,
67
65
  TContext extends Record<string, any> = {},
68
66
  TEvents extends PluvRouterEventConfig<TPlatform, TAuthorize, TContext> = {},
69
67
  > implements IOLike<TAuthorize, TEvents>
@@ -201,6 +199,12 @@ export class PluvServer<
201
199
  private readonly _platform: TPlatform;
202
200
  private readonly _router: PluvRouter<TPlatform, TAuthorize, TContext, TEvents>;
203
201
 
202
+ public get fetch() {
203
+ if (!this._platform._fetch) throw new Error(`\`${this._platform._name}\` does not support \`fetch\``);
204
+
205
+ return this._platform._fetch;
206
+ }
207
+
204
208
  /**
205
209
  * @ignore
206
210
  * @readonly
@@ -226,15 +230,16 @@ export class PluvServer<
226
230
  crdt = noop,
227
231
  debug = false,
228
232
  getInitialStorage,
229
- onRoomDeleted,
230
- onRoomMessage,
231
- onStorageUpdated,
232
- onUserConnected,
233
- onUserDisconnected,
233
+
234
234
  platform,
235
235
  router = new PluvRouter<TPlatform, TAuthorize, TContext, TEvents>({} as TEvents),
236
236
  } = options;
237
237
 
238
+ const { onRoomDeleted, onRoomMessage, onStorageUpdated, onUserConnected, onUserDisconnected } =
239
+ options as Partial<BasePluvIOListeners<TPlatform, TAuthorize, TContext, TEvents>>;
240
+
241
+ platform.validateConfig(options);
242
+
238
243
  this._crdt = crdt;
239
244
  this._debug = debug;
240
245
  this._platform = platform;
@@ -255,7 +260,7 @@ export class PluvServer<
255
260
  onStorageUpdated: (event) => onStorageUpdated?.(event),
256
261
  onUserConnected: (event) => onUserConnected?.(event),
257
262
  onUserDisconnected: (event) => onUserDisconnected?.(event),
258
- } as PluvIOListeners<TPlatform, TAuthorize, TContext, TEvents>;
263
+ } as BasePluvIOListeners<TPlatform, TAuthorize, TContext, TEvents>;
259
264
  }
260
265
 
261
266
  public createRoom(
@@ -269,6 +274,10 @@ export class PluvServer<
269
274
  TEvents
270
275
  >[0] & { _meta?: any };
271
276
 
277
+ if (this._platform._config.handleMode !== "io") {
278
+ throw new Error(`\`createRoom\' is unsupported for \`${this._platform._name}\``);
279
+ }
280
+
272
281
  if (!/^[a-z0-9]+[a-z0-9\-_]+[a-z0-9]+$/i.test(room)) throw new Error("Unsupported room name");
273
282
 
274
283
  const roomContext = platformRoomContext as InferRoomContextType<TPlatform>;
@@ -316,18 +325,33 @@ export class PluvServer<
316
325
  throw new Error("IO does not specify authorize during initialization.");
317
326
  }
318
327
 
319
- const ioAuthorize =
320
- typeof this._authorize === "function" ? this._authorize(params) : (this._authorize as { secret: string });
328
+ /**
329
+ * !HACK
330
+ * @description Allow the platform to overwrite this behavior as needed. This is introduced
331
+ * to support platformPluv
332
+ * @date December 15, 2024
333
+ */
334
+ if (this._platform._createToken) return await this._platform._createToken(params);
321
335
 
322
- const secret = ioAuthorize.secret;
336
+ const ioAuthorize = this._getIOAuthorize(params);
337
+ const secret = ioAuthorize?.secret ?? null;
323
338
 
324
- return await authorize({
325
- platform: this._platform,
326
- secret,
327
- }).encode(params);
339
+ if (!secret) throw new Error("`authorize` was specified without a valid secret");
340
+
341
+ return await authorize({ platform: this._platform, secret }).encode(params);
342
+ }
343
+
344
+ private _getIOAuthorize(
345
+ options: WebsocketRegisterConfig<TPlatform>,
346
+ ): ResolvedPluvIOAuthorize<any, any, any> | null {
347
+ if (typeof this._authorize === "function") {
348
+ return this._authorize(options);
349
+ }
350
+
351
+ return this._authorize as ResolvedPluvIOAuthorize<any, any, any> | null;
328
352
  }
329
353
 
330
- private _getListeners(): PluvIOListeners<TPlatform, TAuthorize, TContext, TEvents> {
354
+ private _getListeners(): BasePluvIOListeners<TPlatform, TAuthorize, TContext, TEvents> {
331
355
  return (this as any)._listeners;
332
356
  }
333
357
 
package/src/createIO.ts CHANGED
@@ -1,7 +1,7 @@
1
- import type { BaseUser, IOAuthorize } from "@pluv/types";
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 } from "./types";
4
+ import type { CrdtLibraryType, PluvContext, PluvIOAuthorize } from "./types";
5
5
 
6
6
  export type CreateIOParams<
7
7
  TPlatform extends AbstractPlatform<any> = AbstractPlatform<any>,
@@ -9,7 +9,7 @@ export type CreateIOParams<
9
9
  TAuthorizeUser extends BaseUser = BaseUser,
10
10
  TAuthorizeRequired extends boolean = false,
11
11
  > = {
12
- authorize?: IOAuthorize<TAuthorizeUser, TAuthorizeRequired, InferInitContextType<TPlatform>>;
12
+ authorize?: PluvIOAuthorize<TPlatform, TAuthorizeUser, TAuthorizeRequired, InferInitContextType<TPlatform>>;
13
13
  context?: PluvContext<TPlatform, TContext>;
14
14
  crdt?: CrdtLibraryType;
15
15
  debug?: boolean;
@@ -23,15 +23,24 @@ export const createIO = <
23
23
  TAuthorizeRequired extends boolean = false,
24
24
  >(
25
25
  params: CreateIOParams<TPlatform, TContext, TAuthorizeUser, TAuthorizeRequired>,
26
- ): PluvIO<TPlatform, IOAuthorize<TAuthorizeUser, TAuthorizeRequired, InferInitContextType<TPlatform>>, TContext> => {
26
+ ): PluvIO<
27
+ TPlatform,
28
+ PluvIOAuthorize<TPlatform, TAuthorizeUser, TAuthorizeRequired, InferInitContextType<TPlatform>>,
29
+ TContext
30
+ > => {
27
31
  const { authorize, context, crdt, debug, platform } = params;
28
32
 
29
33
  return new PluvIO<
30
34
  TPlatform,
31
- IOAuthorize<TAuthorizeUser, TAuthorizeRequired, InferInitContextType<TPlatform>>,
35
+ PluvIOAuthorize<TPlatform, TAuthorizeUser, TAuthorizeRequired, InferInitContextType<TPlatform>>,
32
36
  TContext
33
37
  >({
34
- authorize,
38
+ authorize: authorize as PluvIOAuthorize<
39
+ TPlatform,
40
+ TAuthorizeUser,
41
+ TAuthorizeRequired,
42
+ InferInitContextType<TPlatform>
43
+ >,
35
44
  context,
36
45
  crdt,
37
46
  debug,
package/src/index.ts CHANGED
@@ -7,7 +7,6 @@ export type {
7
7
  InferInitContextType,
8
8
  InferPlatformWebSocketType,
9
9
  InferRoomContextType,
10
- WebSocketRegistrationMode,
11
10
  } from "./AbstractPlatform";
12
11
  export { AbstractPubSub } from "./AbstractPubSub";
13
12
  export type { IOPubSubEventMessage } from "./AbstractPubSub";
@@ -38,12 +37,15 @@ export type { CreateRoomOptions, InferIORoom, PluvServerConfig } from "./PluvSer
38
37
  export type {
39
38
  CrdtLibraryType,
40
39
  GetInitialStorageFn,
40
+ HandleMode,
41
41
  IORoomListenerEvent,
42
42
  IORoomMessageEvent,
43
43
  IOStorageUpdatedEvent,
44
44
  IOUserConnectedEvent,
45
45
  IOUserDisconnectedEvent,
46
+ PlatformConfig,
46
47
  PluvIOListeners,
48
+ WebSocketRegistrationMode,
47
49
  WebSocketSerializedState,
48
50
  WebSocketSession,
49
51
  } from "./types";
package/src/types.ts CHANGED
@@ -1,15 +1,19 @@
1
1
  import type { AbstractCrdtDoc, AbstractCrdtDocFactory } from "@pluv/crdt";
2
2
  import type {
3
3
  BaseIOAuthorize,
4
+ BaseUser,
4
5
  EventRecord,
5
6
  IOAuthorize,
6
7
  Id,
7
8
  InferEventMessage,
8
9
  InferEventsOutput,
9
10
  InferIOAuthorizeUser,
11
+ InputZodLike,
10
12
  JsonObject,
11
13
  Maybe,
12
14
  MaybePromise,
15
+ Spread,
16
+ UndefinedProps,
13
17
  } from "@pluv/types";
14
18
  import type {
15
19
  AbstractPlatform,
@@ -36,15 +40,22 @@ export interface CrdtLibraryType {
36
40
  kind: "loro" | "yjs";
37
41
  }
38
42
 
43
+ export type EventResolverKind = "broadcast" | "self" | "sync";
44
+
39
45
  export type EventResolver<
46
+ TKind extends EventResolverKind = EventResolverKind,
40
47
  TPlatform extends AbstractPlatform = AbstractPlatform,
41
48
  TAuthorize extends IOAuthorize<any, any, InferInitContextType<TPlatform>> = BaseIOAuthorize,
42
49
  TContext extends Record<string, any> = {},
43
50
  TInput extends JsonObject = {},
44
51
  TOutput extends EventRecord<string, any> = {},
45
- > = (data: TInput, context: EventResolverContext<TPlatform, TAuthorize, TContext>) => MaybePromise<TOutput | void>;
52
+ > = (
53
+ data: TInput,
54
+ context: EventResolverContext<TKind, TPlatform, TAuthorize, TContext>,
55
+ ) => MaybePromise<TOutput | void>;
46
56
 
47
57
  export interface EventResolverContext<
58
+ TKind extends EventResolverKind = EventResolverKind,
48
59
  TPlatform extends AbstractPlatform = AbstractPlatform,
49
60
  TAuthorize extends IOAuthorize<any, any, InferInitContextType<TPlatform>> = BaseIOAuthorize,
50
61
  TContext extends Record<string, any> = {},
@@ -52,19 +63,7 @@ export interface EventResolverContext<
52
63
  context: TContext;
53
64
  doc: AbstractCrdtDoc<any>;
54
65
  room: string;
55
- /**
56
- * !HACK
57
- * @description Session should only not exist when invoking the event as a
58
- * "sync" event on another machine where the session doesn't exist. There must
59
- * be a better way to handle this, but going to make this nullable for ease
60
- * for now.
61
- *
62
- * `session` should not be referenced most of the time anyhow (outside of
63
- * internal to this library).
64
- * @author leedavidcs
65
- * @date December 25, 2022
66
- */
67
- session: WebSocketSession<TAuthorize> | null;
66
+ session: TKind extends "sync" ? WebSocketSession<TAuthorize> | null : WebSocketSession<TAuthorize>;
68
67
  sessions: readonly WebSocketSession<TAuthorize>[];
69
68
  }
70
69
 
@@ -115,18 +114,81 @@ export type GetInitialStorageFn<TContext extends Record<string, any>> = (
115
114
  event: GetInitialStorageEvent<TContext>,
116
115
  ) => MaybePromise<Maybe<string>>;
117
116
 
118
- export interface PluvIOListeners<
119
- TPlatform extends AbstractPlatform<any>,
120
- TAuthorize extends IOAuthorize<any, any, InferInitContextType<TPlatform>>,
117
+ export type HandleMode = "io" | "fetch";
118
+ export type WebSocketRegistrationMode = "attached" | "detached";
119
+
120
+ export interface PlatformConfig {
121
+ authorize: {
122
+ required?: boolean;
123
+ secret?: boolean;
124
+ };
125
+ requireAuth?: boolean;
126
+ handleMode: HandleMode;
127
+ registrationMode: WebSocketRegistrationMode;
128
+ listeners: {
129
+ onRoomDeleted?: boolean;
130
+ onRoomMessage?: boolean;
131
+ onStorageUpdated?: boolean;
132
+ onUserConnected?: boolean;
133
+ onUserDisconnected?: boolean;
134
+ };
135
+ }
136
+
137
+ export type ResolvedPluvIOAuthorize<
138
+ TPlatform extends AbstractPlatform<any, any, any, any>,
139
+ TUser extends BaseUser = any,
140
+ TRequired extends boolean = false,
141
+ > = { user: InputZodLike<TUser>; required?: TRequired } & UndefinedProps<
142
+ { secret?: string },
143
+ Exclude<"secret", InferPlatformAuthorizeProperties<TPlatform>>
144
+ >;
145
+
146
+ export type PluvIOAuthorize<
147
+ TPlatform extends AbstractPlatform<any, any, any, any>,
148
+ TUser extends BaseUser = any,
149
+ TRequired extends boolean = false,
150
+ TContext extends Record<string, unknown> = {},
151
+ > =
152
+ | ResolvedPluvIOAuthorize<TPlatform, TUser, TRequired>
153
+ | ((context: TContext) => ResolvedPluvIOAuthorize<TPlatform, TUser, TRequired>);
154
+
155
+ export type BasePluvIOListeners<
156
+ TPlatform extends AbstractPlatform<any, any, any, any>,
157
+ TAuthorize extends PluvIOAuthorize<TPlatform, any, any, InferInitContextType<TPlatform>>,
121
158
  TContext extends Record<string, any>,
122
159
  TEvents extends PluvRouterEventConfig<TPlatform, TAuthorize, TContext>,
123
- > {
160
+ > = {
124
161
  onRoomDeleted: (event: IORoomListenerEvent<TContext>) => void;
125
162
  onRoomMessage: (event: IORoomMessageEvent<TPlatform, TAuthorize, TContext, TEvents>) => void;
126
163
  onStorageUpdated: (event: IOStorageUpdatedEvent<TPlatform, TAuthorize, TContext>) => void;
127
164
  onUserConnected: (event: IOUserConnectedEvent<TPlatform, TAuthorize, TContext>) => void;
128
165
  onUserDisconnected: (event: IOUserDisconnectedEvent<TPlatform, TAuthorize, TContext>) => void;
129
- }
166
+ };
167
+
168
+ export type PluvIOListeners<
169
+ TPlatform extends AbstractPlatform<any, any, any, any>,
170
+ TAuthorize extends PluvIOAuthorize<TPlatform, any, any, InferInitContextType<TPlatform>>,
171
+ TContext extends Record<string, any>,
172
+ TEvents extends PluvRouterEventConfig<TPlatform, TAuthorize, TContext>,
173
+ > = UndefinedProps<
174
+ BasePluvIOListeners<TPlatform, TAuthorize, TContext, TEvents>,
175
+ Exclude<keyof BasePluvIOListeners<TPlatform, TAuthorize, TContext, TEvents>, InferPlatformListeners<TPlatform>>
176
+ >;
177
+
178
+ export type InferPlatformConfig<TPlatform extends AbstractPlatform<any, any, any, any>> =
179
+ TPlatform extends AbstractPlatform<any, any, any, infer IConfig> ? IConfig : never;
180
+
181
+ export type InferPlatformAuthorizeProperties<TPlatform extends AbstractPlatform<any, any, any, any>> = keyof {
182
+ [P in keyof PlatformConfig["authorize"] as InferPlatformConfig<TPlatform>["authorize"][P] extends true | undefined
183
+ ? P
184
+ : never]: true;
185
+ };
186
+
187
+ export type InferPlatformListeners<TPlatform extends AbstractPlatform<any, any, any, any>> = keyof {
188
+ [P in keyof PlatformConfig["listeners"] as InferPlatformConfig<TPlatform>["listeners"][P] extends true | undefined
189
+ ? P
190
+ : never]: true;
191
+ };
130
192
 
131
193
  export type IORoomListenerEvent<TContext extends Record<string, any>> = {
132
194
  context: TContext;
@@ -136,7 +198,7 @@ export type IORoomListenerEvent<TContext extends Record<string, any>> = {
136
198
 
137
199
  export type IORoomMessageEvent<
138
200
  TPlatform extends AbstractPlatform<any>,
139
- TAuthorize extends IOAuthorize<any, any, InferInitContextType<TPlatform>>,
201
+ TAuthorize extends PluvIOAuthorize<TPlatform, any, any, InferInitContextType<TPlatform>>,
140
202
  TContext extends Record<string, any>,
141
203
  TEvents extends PluvRouterEventConfig<TPlatform, TAuthorize, TContext>,
142
204
  > = IORoomListenerEvent<TContext> & {
@@ -1,2 +1,2 @@
1
1
  // Generated by genversion.
2
- export const version = '0.33.0'
2
+ export const version = '0.34.1'